import { describe, it, expect } from 'vitest'; import { ref } from 'vue'; import { useListControls, type FilterDef, type SortDef } from '../src/composables/useListControls'; interface Item { n: number; } const sorts: SortDef[] = [ { key: 'n', labelKey: 'n', compare: (a, b) => a.n - b.n, defaultDir: 'asc' }, ]; const filters: FilterDef[] = [ { key: 'parity', labelKey: 'parity', options: [ { value: 'even', label: 'even' }, { value: 'odd', label: 'odd' }, ], predicate: (it, active) => (active.has('even') && it.n % 2 === 0) || (active.has('odd') && it.n % 2 === 1), }, ]; function make() { const source = ref([{ n: 5 }, { n: 2 }, { n: 4 }, { n: 1 }, { n: 3 }]); const c = useListControls({ source: () => source.value, sorts, filters, defaultPageSize: 2 }); return { source, c }; } describe('useListControls', () => { it('trie en ascendant par défaut', () => { const { c } = make(); expect(c.processed.value.map((i) => i.n)).toEqual([1, 2]); // page 1, taille 2 expect(c.total.value).toBe(5); expect(c.pageCount.value).toBe(3); }); it('inverse la direction au re-clic de la même clé', () => { const { c } = make(); c.setSort('n'); // même clé → desc expect(c.sortDir.value).toBe('desc'); expect(c.processed.value.map((i) => i.n)).toEqual([5, 4]); }); it('pagine et borne la page', () => { const { c } = make(); c.setPage(3); expect(c.processed.value.map((i) => i.n)).toEqual([5]); c.setPage(99); expect(c.page.value).toBe(3); // borné à pageCount }); it('filtre (OR intra-filtre) et revient page 1', () => { const { c } = make(); c.setPage(2); c.toggleFilter('parity', 'even'); expect(c.page.value).toBe(1); expect(c.total.value).toBe(2); // 2 et 4 expect(c.processed.value.map((i) => i.n)).toEqual([2, 4]); }); it('setSearch revient page 1, mais écrire search.value directement (hydratation) ne touche pas la page', () => { const { c } = make(); c.setPage(3); // hydratation URL : on écrit le ref directement → la page fournie par l'URL est préservée c.search.value = ''; expect(c.page.value).toBe(3); // saisie utilisateur via setSearch → retour page 1 c.setSearch('x'); expect(c.page.value).toBe(1); }); it('pageSize 0 affiche tout', () => { const { c } = make(); c.setPageSize(0); expect(c.pageCount.value).toBe(1); expect(c.processed.value.map((i) => i.n)).toEqual([1, 2, 3, 4, 5]); }); it('reste réactif aux mutations de la source (upsert temps réel)', () => { const { source, c } = make(); source.value = [...source.value, { n: 0 }]; expect(c.total.value).toBe(6); expect(c.processed.value.map((i) => i.n)).toEqual([0, 1]); }); });