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 { h } from 'vue'
|
||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
import type { DefineComponent } from 'vue'
|
import type { DefineComponent } from 'vue'
|
||||||
@@ -189,24 +189,6 @@ describe('MalioDataTable', () => {
|
|||||||
expect(wrapper.find('[data-test="pagination"]').exists()).toBe(true)
|
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', () => {
|
it('Prev button is disabled on page 1', () => {
|
||||||
const wrapper = mountComponent({ totalItems: 50, perPage: 10, page: 1 })
|
const wrapper = mountComponent({ totalItems: 50, perPage: 10, page: 1 })
|
||||||
expect(wrapper.find('[data-test="prev-button"]').attributes('disabled')).toBeDefined()
|
expect(wrapper.find('[data-test="prev-button"]').attributes('disabled')).toBeDefined()
|
||||||
@@ -229,26 +211,6 @@ describe('MalioDataTable', () => {
|
|||||||
expect(wrapper.emitted('update:page')?.[0]).toEqual([4])
|
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', () => {
|
it('pagination nav has aria-label', () => {
|
||||||
const wrapper = mountComponent({ totalItems: 30 })
|
const wrapper = mountComponent({ totalItems: 30 })
|
||||||
expect(wrapper.find('[data-test="pagination-nav"]').attributes('aria-label')).toBe('Pagination')
|
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', () => {
|
describe('Per-page selector', () => {
|
||||||
it('emits update:per-page and reset page to 1 on change', async () => {
|
it('emits update:per-page and reset page to 1 on change', async () => {
|
||||||
const wrapper = mountComponent({ totalItems: 100, perPage: 10, page: 5 })
|
const wrapper = mountComponent({ totalItems: 100, perPage: 10, page: 5 })
|
||||||
|
|||||||
Reference in New Issue
Block a user