Skip to content

Commit 2509773

Browse files
committed
test: update structure filters tests
1 parent 3d4eb1e commit 2509773

1 file changed

Lines changed: 76 additions & 44 deletions

File tree

test/nuxt/composables/structured-filters.spec.ts

Lines changed: 76 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { describe, expect, it } from 'vitest'
2+
import { mountSuspended } from '@nuxt/test-utils/runtime'
23
import type { NpmSearchResult } from '#shared/types'
34

45
// Helper to create mock package results
@@ -29,40 +30,60 @@ function createPackage(overrides: {
2930
}
3031
}
3132

33+
/**
34+
* Helper to test useStructuredFilters by wrapping it in a component.
35+
* This is required because the composable uses useI18n which must be
36+
* called inside a Vue component's setup function.
37+
*/
38+
async function useStructuredFiltersInComponent(packages: Ref<NpmSearchResult[]>) {
39+
let capturedResult: ReturnType<typeof useStructuredFilters>
40+
41+
const WrapperComponent = defineComponent({
42+
setup() {
43+
capturedResult = useStructuredFilters({ packages })
44+
return () => h('div')
45+
},
46+
})
47+
48+
await mountSuspended(WrapperComponent)
49+
50+
return capturedResult!
51+
}
52+
3253
describe('useStructuredFilters', () => {
3354
describe('keyword filtering (AND logic)', () => {
34-
it('returns all packages when no keywords selected', () => {
55+
it('returns all packages when no keywords selected', async () => {
3556
const packages = ref([
3657
createPackage({ name: 'pkg-a', keywords: ['react'] }),
3758
createPackage({ name: 'pkg-b', keywords: ['vue'] }),
3859
])
3960

40-
const { sortedPackages } = useStructuredFilters({ packages })
61+
const { sortedPackages } = await useStructuredFiltersInComponent(packages)
4162

4263
expect(sortedPackages.value).toHaveLength(2)
4364
})
4465

45-
it('filters to packages with single keyword', () => {
66+
it('filters to packages with single keyword', async () => {
4667
const packages = ref([
4768
createPackage({ name: 'pkg-a', keywords: ['react', 'hooks'] }),
4869
createPackage({ name: 'pkg-b', keywords: ['vue'] }),
4970
])
5071

51-
const { sortedPackages, addKeyword } = useStructuredFilters({ packages })
72+
const { sortedPackages, addKeyword } = await useStructuredFiltersInComponent(packages)
5273
addKeyword('react')
5374

5475
expect(sortedPackages.value).toHaveLength(1)
5576
expect(sortedPackages.value[0]!.package.name).toBe('pkg-a')
5677
})
5778

58-
it('uses AND logic for multiple keywords', () => {
79+
it('uses AND logic for multiple keywords', async () => {
5980
const packages = ref([
6081
createPackage({ name: 'pkg-a', keywords: ['react', 'hooks'] }),
6182
createPackage({ name: 'pkg-b', keywords: ['react', 'state'] }),
6283
createPackage({ name: 'pkg-c', keywords: ['react', 'hooks', 'state'] }),
6384
])
6485

65-
const { sortedPackages, addKeyword } = useStructuredFilters({ packages })
86+
const { sortedPackages, addKeyword } = await useStructuredFiltersInComponent(packages)
6687
addKeyword('react')
6788
addKeyword('hooks')
6889

@@ -72,13 +93,13 @@ describe('useStructuredFilters', () => {
7293
expect(sortedPackages.value.map(p => p.package.name)).toContain('pkg-c')
7394
})
7495

75-
it('returns empty when no package has all keywords', () => {
96+
it('returns empty when no package has all keywords', async () => {
7697
const packages = ref([
7798
createPackage({ name: 'pkg-a', keywords: ['react'] }),
7899
createPackage({ name: 'pkg-b', keywords: ['hooks'] }),
79100
])
80101

81-
const { sortedPackages, addKeyword } = useStructuredFilters({ packages })
102+
const { sortedPackages, addKeyword } = await useStructuredFiltersInComponent(packages)
82103
addKeyword('react')
83104
addKeyword('hooks')
84105

@@ -87,56 +108,60 @@ describe('useStructuredFilters', () => {
87108
})
88109

89110
describe('text filtering', () => {
90-
it('filters by name when scope is name', () => {
111+
it('filters by name when scope is name', async () => {
91112
const packages = ref([
92113
createPackage({ name: 'react-query', description: 'Data fetching' }),
93114
createPackage({ name: 'vue-query', description: 'Data fetching for Vue' }),
94115
])
95116

96-
const { sortedPackages, setTextFilter, setSearchScope } = useStructuredFilters({ packages })
117+
const { sortedPackages, setTextFilter, setSearchScope } =
118+
await useStructuredFiltersInComponent(packages)
97119
setSearchScope('name')
98120
setTextFilter('react')
99121

100122
expect(sortedPackages.value).toHaveLength(1)
101123
expect(sortedPackages.value[0]!.package.name).toBe('react-query')
102124
})
103125

104-
it('filters by description when scope is description', () => {
126+
it('filters by description when scope is description', async () => {
105127
const packages = ref([
106128
createPackage({ name: 'pkg-a', description: 'A React component library' }),
107129
createPackage({ name: 'pkg-b', description: 'A Vue component library' }),
108130
])
109131

110-
const { sortedPackages, setTextFilter, setSearchScope } = useStructuredFilters({ packages })
132+
const { sortedPackages, setTextFilter, setSearchScope } =
133+
await useStructuredFiltersInComponent(packages)
111134
setSearchScope('description')
112135
setTextFilter('React')
113136

114137
expect(sortedPackages.value).toHaveLength(1)
115138
expect(sortedPackages.value[0]!.package.name).toBe('pkg-a')
116139
})
117140

118-
it('filters by keywords when scope is keywords', () => {
141+
it('filters by keywords when scope is keywords', async () => {
119142
const packages = ref([
120143
createPackage({ name: 'pkg-a', keywords: ['typescript', 'react'] }),
121144
createPackage({ name: 'pkg-b', keywords: ['javascript', 'vue'] }),
122145
])
123146

124-
const { sortedPackages, setTextFilter, setSearchScope } = useStructuredFilters({ packages })
147+
const { sortedPackages, setTextFilter, setSearchScope } =
148+
await useStructuredFiltersInComponent(packages)
125149
setSearchScope('keywords')
126150
setTextFilter('type')
127151

128152
expect(sortedPackages.value).toHaveLength(1)
129153
expect(sortedPackages.value[0]!.package.name).toBe('pkg-a')
130154
})
131155

132-
it('filters by all fields when scope is all', () => {
156+
it('filters by all fields when scope is all', async () => {
133157
const packages = ref([
134158
createPackage({ name: 'pkg-a', description: 'foo', keywords: ['bar'] }),
135159
createPackage({ name: 'pkg-b', description: 'baz', keywords: ['qux'] }),
136160
createPackage({ name: 'search-term', description: 'other', keywords: [] }),
137161
])
138162

139-
const { sortedPackages, setTextFilter, setSearchScope } = useStructuredFilters({ packages })
163+
const { sortedPackages, setTextFilter, setSearchScope } =
164+
await useStructuredFiltersInComponent(packages)
140165
setSearchScope('all')
141166
setTextFilter('search-term')
142167

@@ -146,71 +171,76 @@ describe('useStructuredFilters', () => {
146171
})
147172

148173
describe('text filtering with operators', () => {
149-
it('parses name: operator in all scope', () => {
174+
it('parses name: operator in all scope', async () => {
150175
const packages = ref([
151176
createPackage({ name: 'react-query', description: 'vue stuff' }),
152177
createPackage({ name: 'vue-query', description: 'react stuff' }),
153178
])
154179

155-
const { sortedPackages, setTextFilter, setSearchScope } = useStructuredFilters({ packages })
180+
const { sortedPackages, setTextFilter, setSearchScope } =
181+
await useStructuredFiltersInComponent(packages)
156182
setSearchScope('all')
157183
setTextFilter('name:react')
158184

159185
expect(sortedPackages.value).toHaveLength(1)
160186
expect(sortedPackages.value[0]!.package.name).toBe('react-query')
161187
})
162188

163-
it('parses desc: operator in all scope', () => {
189+
it('parses desc: operator in all scope', async () => {
164190
const packages = ref([
165191
createPackage({ name: 'pkg-a', description: 'A fantastic library' }),
166192
createPackage({ name: 'pkg-b', description: 'A mediocre library' }),
167193
])
168194

169-
const { sortedPackages, setTextFilter, setSearchScope } = useStructuredFilters({ packages })
195+
const { sortedPackages, setTextFilter, setSearchScope } =
196+
await useStructuredFiltersInComponent(packages)
170197
setSearchScope('all')
171198
setTextFilter('desc:fantastic')
172199

173200
expect(sortedPackages.value).toHaveLength(1)
174201
expect(sortedPackages.value[0]!.package.name).toBe('pkg-a')
175202
})
176203

177-
it('parses kw: operator in all scope', () => {
204+
it('parses kw: operator in all scope', async () => {
178205
const packages = ref([
179206
createPackage({ name: 'pkg-a', keywords: ['typescript'] }),
180207
createPackage({ name: 'pkg-b', keywords: ['javascript'] }),
181208
])
182209

183-
const { sortedPackages, setTextFilter, setSearchScope } = useStructuredFilters({ packages })
210+
const { sortedPackages, setTextFilter, setSearchScope } =
211+
await useStructuredFiltersInComponent(packages)
184212
setSearchScope('all')
185213
setTextFilter('kw:typescript')
186214

187215
expect(sortedPackages.value).toHaveLength(1)
188216
expect(sortedPackages.value[0]!.package.name).toBe('pkg-a')
189217
})
190218

191-
it('combines multiple operators with AND logic', () => {
219+
it('combines multiple operators with AND logic', async () => {
192220
const packages = ref([
193221
createPackage({ name: 'react-lib', description: 'hooks library', keywords: ['react'] }),
194222
createPackage({ name: 'react-other', description: 'other stuff', keywords: ['react'] }),
195223
createPackage({ name: 'vue-lib', description: 'hooks library', keywords: ['vue'] }),
196224
])
197225

198-
const { sortedPackages, setTextFilter, setSearchScope } = useStructuredFilters({ packages })
226+
const { sortedPackages, setTextFilter, setSearchScope } =
227+
await useStructuredFiltersInComponent(packages)
199228
setSearchScope('all')
200229
setTextFilter('name:react desc:hooks')
201230

202231
expect(sortedPackages.value).toHaveLength(1)
203232
expect(sortedPackages.value[0]!.package.name).toBe('react-lib')
204233
})
205234

206-
it('handles comma-separated keyword values with OR logic', () => {
235+
it('handles comma-separated keyword values with OR logic', async () => {
207236
const packages = ref([
208237
createPackage({ name: 'pkg-a', keywords: ['react'] }),
209238
createPackage({ name: 'pkg-b', keywords: ['vue'] }),
210239
createPackage({ name: 'pkg-c', keywords: ['angular'] }),
211240
])
212241

213-
const { sortedPackages, setTextFilter, setSearchScope } = useStructuredFilters({ packages })
242+
const { sortedPackages, setTextFilter, setSearchScope } =
243+
await useStructuredFiltersInComponent(packages)
214244
setSearchScope('all')
215245
setTextFilter('kw:react,vue')
216246

@@ -219,7 +249,7 @@ describe('useStructuredFilters', () => {
219249
expect(sortedPackages.value.map(p => p.package.name)).toContain('pkg-b')
220250
})
221251

222-
it('combines operators with remaining text', () => {
252+
it('combines operators with remaining text', async () => {
223253
const packages = ref([
224254
createPackage({
225255
name: 'react-query',
@@ -234,7 +264,8 @@ describe('useStructuredFilters', () => {
234264
}),
235265
])
236266

237-
const { sortedPackages, setTextFilter, setSearchScope } = useStructuredFilters({ packages })
267+
const { sortedPackages, setTextFilter, setSearchScope } =
268+
await useStructuredFiltersInComponent(packages)
238269
setSearchScope('all')
239270
setTextFilter('name:react fetching')
240271

@@ -244,26 +275,26 @@ describe('useStructuredFilters', () => {
244275
})
245276

246277
describe('download range filtering', () => {
247-
it('filters packages below threshold', () => {
278+
it('filters packages below threshold', async () => {
248279
const packages = ref([
249280
createPackage({ name: 'popular', downloads: 50000 }),
250281
createPackage({ name: 'unpopular', downloads: 50 }),
251282
])
252283

253-
const { sortedPackages, setDownloadRange } = useStructuredFilters({ packages })
284+
const { sortedPackages, setDownloadRange } = await useStructuredFiltersInComponent(packages)
254285
setDownloadRange('gt100k')
255286

256287
expect(sortedPackages.value).toHaveLength(0)
257288
})
258289

259-
it('filters packages within range', () => {
290+
it('filters packages within range', async () => {
260291
const packages = ref([
261292
createPackage({ name: 'pkg-a', downloads: 500 }),
262293
createPackage({ name: 'pkg-b', downloads: 5000 }),
263294
createPackage({ name: 'pkg-c', downloads: 50000 }),
264295
])
265296

266-
const { sortedPackages, setDownloadRange } = useStructuredFilters({ packages })
297+
const { sortedPackages, setDownloadRange } = await useStructuredFiltersInComponent(packages)
267298
setDownloadRange('1k-10k')
268299

269300
expect(sortedPackages.value).toHaveLength(1)
@@ -272,59 +303,59 @@ describe('useStructuredFilters', () => {
272303
})
273304

274305
describe('sorting', () => {
275-
it('sorts by downloads descending by default with downloads sort', () => {
306+
it('sorts by downloads descending by default with downloads sort', async () => {
276307
const packages = ref([
277308
createPackage({ name: 'pkg-a', downloads: 100 }),
278309
createPackage({ name: 'pkg-b', downloads: 1000 }),
279310
createPackage({ name: 'pkg-c', downloads: 500 }),
280311
])
281312

282-
const { sortedPackages, setSort } = useStructuredFilters({ packages })
313+
const { sortedPackages, setSort } = await useStructuredFiltersInComponent(packages)
283314
setSort('downloads-week-desc')
284315

285316
expect(sortedPackages.value[0]!.package.name).toBe('pkg-b')
286317
expect(sortedPackages.value[1]!.package.name).toBe('pkg-c')
287318
expect(sortedPackages.value[2]!.package.name).toBe('pkg-a')
288319
})
289320

290-
it('sorts by name ascending', () => {
321+
it('sorts by name ascending', async () => {
291322
const packages = ref([
292323
createPackage({ name: 'zlib' }),
293324
createPackage({ name: 'axios' }),
294325
createPackage({ name: 'lodash' }),
295326
])
296327

297-
const { sortedPackages, setSort } = useStructuredFilters({ packages })
328+
const { sortedPackages, setSort } = await useStructuredFiltersInComponent(packages)
298329
setSort('name-asc')
299330

300331
expect(sortedPackages.value[0]!.package.name).toBe('axios')
301332
expect(sortedPackages.value[1]!.package.name).toBe('lodash')
302333
expect(sortedPackages.value[2]!.package.name).toBe('zlib')
303334
})
304335

305-
it('sorts by updated date descending', () => {
336+
it('sorts by updated date descending', async () => {
306337
const packages = ref([
307338
createPackage({ name: 'old', updated: '2023-01-01T00:00:00.000Z' }),
308339
createPackage({ name: 'new', updated: '2024-06-01T00:00:00.000Z' }),
309340
createPackage({ name: 'mid', updated: '2024-01-01T00:00:00.000Z' }),
310341
])
311342

312-
const { sortedPackages, setSort } = useStructuredFilters({ packages })
343+
const { sortedPackages, setSort } = await useStructuredFiltersInComponent(packages)
313344
setSort('updated-desc')
314345

315346
expect(sortedPackages.value[0]!.package.name).toBe('new')
316347
expect(sortedPackages.value[1]!.package.name).toBe('mid')
317348
expect(sortedPackages.value[2]!.package.name).toBe('old')
318349
})
319350

320-
it('relevance sort preserves original order', () => {
351+
it('relevance sort preserves original order', async () => {
321352
const packages = ref([
322353
createPackage({ name: 'first', downloads: 100 }),
323354
createPackage({ name: 'second', downloads: 1000 }),
324355
createPackage({ name: 'third', downloads: 500 }),
325356
])
326357

327-
const { sortedPackages, setSort } = useStructuredFilters({ packages })
358+
const { sortedPackages, setSort } = await useStructuredFiltersInComponent(packages)
328359
setSort('relevance-desc')
329360

330361
// Relevance should preserve the original order from the server
@@ -335,14 +366,14 @@ describe('useStructuredFilters', () => {
335366
})
336367

337368
describe('clearing filters', () => {
338-
it('clearAllFilters resets all filters', () => {
369+
it('clearAllFilters resets all filters', async () => {
339370
const packages = ref([
340371
createPackage({ name: 'pkg-a', keywords: ['react'], downloads: 1000 }),
341372
createPackage({ name: 'pkg-b', keywords: ['vue'], downloads: 500 }),
342373
])
343374

344375
const { sortedPackages, setTextFilter, addKeyword, setDownloadRange, clearAllFilters } =
345-
useStructuredFilters({ packages })
376+
await useStructuredFiltersInComponent(packages)
346377

347378
setTextFilter('pkg-a')
348379
addKeyword('react')
@@ -355,13 +386,14 @@ describe('useStructuredFilters', () => {
355386
expect(sortedPackages.value).toHaveLength(2)
356387
})
357388

358-
it('removeKeyword removes specific keyword', () => {
389+
it('removeKeyword removes specific keyword', async () => {
359390
const packages = ref([
360391
createPackage({ name: 'pkg-a', keywords: ['react', 'hooks'] }),
361392
createPackage({ name: 'pkg-b', keywords: ['react'] }),
362393
])
363394

364-
const { sortedPackages, addKeyword, removeKeyword } = useStructuredFilters({ packages })
395+
const { sortedPackages, addKeyword, removeKeyword } =
396+
await useStructuredFiltersInComponent(packages)
365397

366398
addKeyword('react')
367399
addKeyword('hooks')

0 commit comments

Comments
 (0)