- 41 unit and component suites under admin/tests/{app,state,shell,list,form,relation,views,ui}
covering states and a11y roles; every src module is imported by a test
- typed fixture helper assigns each JSON fixture to its generated OpenAPI type
- fix: iconFor ignores inherited object members such as "constructor"
- fix: field controls import ./control instead of the registry (import cycle
left a renderer unregistered depending on module load order)
- fix: dropdown shows the placeholder for an unknown stored value next to an emptyOption
- fix: list announces a failed schema load even when the rows arrive after it
- tailwind no longer scans admin/tests; boardwalk/dist rebuilt
85 lines
4.0 KiB
TypeScript
85 lines
4.0 KiB
TypeScript
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]])
|
||
})
|
||
})
|