Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
76 lines
3.0 KiB
TypeScript
76 lines
3.0 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
|
|
import { buildListParams, getColumnFilterConfig, serializeFilters, withRowKeys } from '@/components/paginated-list/paginatedListUtils'
|
|
import type { PaginationListColumnType } from '@/types'
|
|
|
|
describe('paginatedListUtils', () => {
|
|
it('serializes scalar and range filters without mutating the input', () => {
|
|
const filters = { status: 'active', price: { from: '10', to: '20' }, ignored: '' }
|
|
|
|
expect(serializeFilters(filters)).toEqual({ status: 'active', price: '10,20' })
|
|
expect(filters.price).toEqual({ from: '10', to: '20' })
|
|
})
|
|
|
|
it('merges inherited filters and applies an optional API prefix', () => {
|
|
expect(
|
|
buildListParams({
|
|
filterPrefix: 'booking',
|
|
filters: { status: 'paid' },
|
|
page: 2,
|
|
rowsPerPage: 30,
|
|
sort: '-createdAt',
|
|
urlParams: { page: 1, pageSize: 20, filters: { owner: 'me' } },
|
|
})
|
|
).toEqual({
|
|
'booking.page': 2,
|
|
'booking.pageSize': 30,
|
|
'booking.filters': { owner: 'me', status: 'paid' },
|
|
'booking.sort': '-createdAt',
|
|
})
|
|
})
|
|
|
|
it('creates stable row keys from row id, customer id, or index', () => {
|
|
expect(withRowKeys([{ id: 7 }, { customer: { id: 'customer-1' } }, { title: 'fallback' }])).toEqual([
|
|
{ id: '7' },
|
|
{ customer: { id: 'customer-1' }, id: 'customer-1' },
|
|
{ title: 'fallback', id: 'row-2' },
|
|
])
|
|
})
|
|
|
|
// getColumnFilterConfig is the single source of truth both
|
|
// PaginatedListColumnFilter (inline) and PaginatedListFilterModal (modal)
|
|
// dispatch off of via PaginatedListFilterField (FE-4-T1) — locking down
|
|
// this mapping is what keeps the two call sites structurally unable to
|
|
// diverge for a new column type, in place of testing each consumer
|
|
// separately.
|
|
describe('getColumnFilterConfig', () => {
|
|
const column = (type?: PaginationListColumnType['type'], filterItems?: unknown[]) =>
|
|
({ field: 'f', label: 'F', type, filterItems }) as PaginationListColumnType
|
|
|
|
it('maps text, number, and untyped columns to scalar', () => {
|
|
expect(getColumnFilterConfig(column(undefined))).toBe('scalar')
|
|
expect(getColumnFilterConfig(column('text'))).toBe('scalar')
|
|
expect(getColumnFilterConfig(column('number'))).toBe('scalar')
|
|
})
|
|
|
|
it('maps inputFromTo to range', () => {
|
|
expect(getColumnFilterConfig(column('inputFromTo'))).toBe('range')
|
|
})
|
|
|
|
it('maps select to select only when filterItems are present, else none', () => {
|
|
expect(getColumnFilterConfig(column('select', [{ code: '1', name: 'One' }]))).toBe('select')
|
|
expect(getColumnFilterConfig(column('select', []))).toBe('none')
|
|
expect(getColumnFilterConfig(column('select'))).toBe('none')
|
|
})
|
|
|
|
it('maps date to date and dateFromTo to dateRange', () => {
|
|
expect(getColumnFilterConfig(column('date'))).toBe('date')
|
|
expect(getColumnFilterConfig(column('dateFromTo'))).toBe('dateRange')
|
|
})
|
|
|
|
it('falls back to none for an unrecognized type', () => {
|
|
expect(getColumnFilterConfig(column('somethingNew' as never))).toBe('none')
|
|
})
|
|
})
|
|
})
|