import { beforeEach, describe, expect, it } from 'vitest' import { mount } from '@vue/test-utils' import Pagination from '../../src/components/list/Pagination.vue' import type { ListMeta } from '../../src/api/types' import { resetState } from '../helpers' function meta(page: number, lastPage: number, total = lastPage * 20, perPage = 20): ListMeta { return { page, last_page: lastPage, total, per_page: perPage } } function pager(page: number, lastPage: number) { const wrapper = mount(Pagination, { props: { meta: meta(page, lastPage), loading: false, perPageOptions: [20], perPage: 20 } }) return wrapper .findAll('nav > *') .filter((element) => !['prev', 'next'].includes(element.attributes('data-page') ?? '')) .map((element) => element.text()) .join(' ') } beforeEach(() => { resetState() }) describe('pagination', () => { it('shows the range of the page and a labelled pager', () => { const wrapper = mount(Pagination, { props: { meta: meta(2, 3, 45), loading: false, perPageOptions: [20], perPage: 20 } }) expect(wrapper.find('[data-range]').text()).toBe('21–40 z 45') expect(wrapper.find('nav').attributes('aria-label')).toBe('Stronicowanie') expect(wrapper.find('[data-page="2"]').attributes('aria-current')).toBe('page') expect(wrapper.find('[data-page="1"]').attributes('aria-current')).toBeUndefined() }) it.each([ [1, 1, '1'], [1, 5, '1 2 3 … 5'], [3, 5, '1 2 3 4 5'], [5, 10, '1 … 4 5 6 … 10'], [10, 10, '1 … 8 9 10'], [2, 3, '1 2 3'], ])('page %i of %i shows %s', (page, last, expected) => { expect(pager(page, last)).toBe(expected) }) it('disables prev on the first and next on the last page and emits pages', async () => { const wrapper = mount(Pagination, { props: { meta: meta(1, 3), loading: false, perPageOptions: [20], perPage: 20 } }) expect(wrapper.find('[data-page="prev"]').attributes('disabled')).toBeDefined() expect(wrapper.find('[data-page="next"]').attributes('disabled')).toBeUndefined() await wrapper.find('[data-page="next"]').trigger('click') await wrapper.find('[data-page="3"]').trigger('click') await wrapper.find('[data-page="1"]').trigger('click') expect(wrapper.emitted('page')).toEqual([[2], [3]]) await wrapper.setProps({ meta: meta(3, 3) }) expect(wrapper.find('[data-page="next"]').attributes('disabled')).toBeDefined() await wrapper.find('[data-page="prev"]').trigger('click') expect(wrapper.emitted('page')!.at(-1)).toEqual([2]) }) it('shows the plural zero-results message and no pager without rows', () => { const wrapper = mount(Pagination, { props: { meta: meta(1, 0, 0), loading: false, perPageOptions: [20], perPage: 20 } }) expect(wrapper.find('[data-range]').text()).toBe('0 wyników') expect(wrapper.find('nav').exists()).toBe(false) const none = mount(Pagination, { props: { meta: null, loading: false, perPageOptions: [20], perPage: 20 } }) expect(none.find('[data-range]').text()).toBe('0 wyników') }) it('shows the loading text and hides the pager while loading', () => { const wrapper = mount(Pagination, { props: { meta: meta(1, 2), loading: true, perPageOptions: [20], perPage: 20 } }) expect(wrapper.find('[data-range]').text()).toBe('Wczytywanie…') expect(wrapper.find('nav').exists()).toBe(false) }) it('offers the per-page select only with more than one option and emits a valid choice', async () => { const one = mount(Pagination, { props: { meta: meta(1, 2), loading: false, perPageOptions: [20], perPage: 20 } }) expect(one.find('[data-per-page]').exists()).toBe(false) const wrapper = mount(Pagination, { props: { meta: meta(1, 2), loading: false, perPageOptions: [10, 20, 50], perPage: 20 } }) const select = wrapper.find('[data-per-page]') expect(select.findAll('option').map((option) => option.text())).toEqual(['10', '20', '50']) expect((select.element as HTMLSelectElement).value).toBe('20') await select.setValue('50') expect(wrapper.emitted('perPage')).toEqual([[50]]) }) })