test(datatable) : champ de saut de page (debounce, Entrée, clamp)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest'
|
||||
import { h } from 'vue'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import type { DefineComponent } from 'vue'
|
||||
@@ -189,24 +189,6 @@ describe('MalioDataTable', () => {
|
||||
expect(wrapper.find('[data-test="pagination"]').exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('renders all pages when totalPages <= 5', () => {
|
||||
const wrapper = mountComponent({ totalItems: 50, perPage: 10 })
|
||||
for (let i = 1; i <= 5; i++) {
|
||||
expect(wrapper.find(`[data-test="page-${i}"]`).exists()).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
it('highlights current page', () => {
|
||||
const wrapper = mountComponent({ totalItems: 50, perPage: 10, page: 3 })
|
||||
expect(wrapper.find('[data-test="page-3"]').attributes('aria-current')).toBe('page')
|
||||
})
|
||||
|
||||
it('emits update:page on page button click', async () => {
|
||||
const wrapper = mountComponent({ totalItems: 50, perPage: 10, page: 1 })
|
||||
await wrapper.find('[data-test="page-3"]').trigger('click')
|
||||
expect(wrapper.emitted('update:page')?.[0]).toEqual([3])
|
||||
})
|
||||
|
||||
it('Prev button is disabled on page 1', () => {
|
||||
const wrapper = mountComponent({ totalItems: 50, perPage: 10, page: 1 })
|
||||
expect(wrapper.find('[data-test="prev-button"]').attributes('disabled')).toBeDefined()
|
||||
@@ -229,26 +211,6 @@ describe('MalioDataTable', () => {
|
||||
expect(wrapper.emitted('update:page')?.[0]).toEqual([4])
|
||||
})
|
||||
|
||||
it('shows ellipsis for truncated pages (> 5 pages)', () => {
|
||||
const wrapper = mountComponent({ totalItems: 200, perPage: 10, page: 10 })
|
||||
const ellipsis = wrapper.findAll('[aria-hidden="true"]')
|
||||
expect(ellipsis.length).toBeGreaterThan(0)
|
||||
expect(ellipsis[0].text()).toBe('…')
|
||||
})
|
||||
|
||||
it('always shows first and last page when > 5 pages', () => {
|
||||
const wrapper = mountComponent({ totalItems: 200, perPage: 10, page: 10 })
|
||||
expect(wrapper.find('[data-test="page-1"]').exists()).toBe(true)
|
||||
expect(wrapper.find('[data-test="page-20"]').exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('shows 1 neighbor on each side of current page', () => {
|
||||
const wrapper = mountComponent({ totalItems: 200, perPage: 10, page: 10 })
|
||||
expect(wrapper.find('[data-test="page-9"]').exists()).toBe(true)
|
||||
expect(wrapper.find('[data-test="page-10"]').exists()).toBe(true)
|
||||
expect(wrapper.find('[data-test="page-11"]').exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('pagination nav has aria-label', () => {
|
||||
const wrapper = mountComponent({ totalItems: 30 })
|
||||
expect(wrapper.find('[data-test="pagination-nav"]').attributes('aria-label')).toBe('Pagination')
|
||||
@@ -265,6 +227,80 @@ describe('MalioDataTable', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('Pagination — saut de page (champ)', () => {
|
||||
beforeEach(() => { vi.useFakeTimers() })
|
||||
afterEach(() => { vi.runOnlyPendingTimers(); vi.useRealTimers() })
|
||||
|
||||
it('affiche la page courante et le total dans le champ', () => {
|
||||
const wrapper = mountComponent({ totalItems: 310, perPage: 10, page: 16 })
|
||||
expect((wrapper.find('[data-test="page-input"]').element as HTMLInputElement).value).toBe('16')
|
||||
expect(wrapper.find('[data-test="total-pages"]').text()).toBe('31')
|
||||
})
|
||||
|
||||
it('émet update:page après le debounce pour une valeur valide', async () => {
|
||||
const wrapper = mountComponent({ totalItems: 310, perPage: 10, page: 1 })
|
||||
const input = wrapper.find('[data-test="page-input"]')
|
||||
await input.setValue('16')
|
||||
expect(wrapper.emitted('update:page')).toBeUndefined()
|
||||
vi.advanceTimersByTime(400)
|
||||
expect(wrapper.emitted('update:page')?.at(-1)).toEqual([16])
|
||||
})
|
||||
|
||||
it('n\'émet pas avant la fin du debounce', async () => {
|
||||
const wrapper = mountComponent({ totalItems: 310, perPage: 10, page: 1 })
|
||||
await wrapper.find('[data-test="page-input"]').setValue('16')
|
||||
vi.advanceTimersByTime(399)
|
||||
expect(wrapper.emitted('update:page')).toBeUndefined()
|
||||
})
|
||||
|
||||
it('Entrée applique immédiatement', async () => {
|
||||
const wrapper = mountComponent({ totalItems: 310, perPage: 10, page: 1 })
|
||||
const input = wrapper.find('[data-test="page-input"]')
|
||||
await input.setValue('16')
|
||||
await input.trigger('keydown.enter')
|
||||
expect(wrapper.emitted('update:page')?.at(-1)).toEqual([16])
|
||||
})
|
||||
|
||||
it('clampe une valeur > N à la dernière page (Entrée)', async () => {
|
||||
const wrapper = mountComponent({ totalItems: 310, perPage: 10, page: 1 })
|
||||
const input = wrapper.find('[data-test="page-input"]')
|
||||
await input.setValue('50')
|
||||
await input.trigger('keydown.enter')
|
||||
expect(wrapper.emitted('update:page')?.at(-1)).toEqual([31])
|
||||
})
|
||||
|
||||
it('restaure la page courante quand le champ est vidé au blur', async () => {
|
||||
const wrapper = mountComponent({ totalItems: 310, perPage: 10, page: 5 })
|
||||
const input = wrapper.find('[data-test="page-input"]')
|
||||
await input.setValue('')
|
||||
await input.trigger('blur')
|
||||
expect(wrapper.emitted('update:page')).toBeUndefined()
|
||||
expect((input.element as HTMLInputElement).value).toBe('5')
|
||||
})
|
||||
|
||||
it('n\'émet pas pour 0 et restaure la page courante (Entrée)', async () => {
|
||||
const wrapper = mountComponent({ totalItems: 310, perPage: 10, page: 5 })
|
||||
const input = wrapper.find('[data-test="page-input"]')
|
||||
await input.setValue('0')
|
||||
await input.trigger('keydown.enter')
|
||||
expect(wrapper.emitted('update:page')).toBeUndefined()
|
||||
expect((input.element as HTMLInputElement).value).toBe('5')
|
||||
})
|
||||
|
||||
it('retire les caractères non numériques à la frappe', async () => {
|
||||
const wrapper = mountComponent({ totalItems: 310, perPage: 10, page: 1 })
|
||||
const input = wrapper.find('[data-test="page-input"]')
|
||||
await input.setValue('1a2b')
|
||||
expect((input.element as HTMLInputElement).value).toBe('12')
|
||||
})
|
||||
|
||||
it('resynchronise le champ quand la prop page change', async () => {
|
||||
const wrapper = mountComponent({ totalItems: 310, perPage: 10, page: 1 })
|
||||
await wrapper.setProps({ page: 7 })
|
||||
expect((wrapper.find('[data-test="page-input"]').element as HTMLInputElement).value).toBe('7')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Per-page selector', () => {
|
||||
it('emits update:per-page and reset page to 1 on change', async () => {
|
||||
const wrapper = mountComponent({ totalItems: 100, perPage: 10, page: 5 })
|
||||
|
||||
Reference in New Issue
Block a user