- components/shared/sort-header.tsx: generic <SortHeader<TKey>> met active-state (ArrowUp/ArrowDown) en inactive (ArrowUpDown). Hergebruik voor zowel /ideas als /dashboard products-tabel. - components/ideas/idea-list.tsx: refactor; lokale SortHeader-helper + ArrowUp/Down/UpDown imports vervangen door shared import. - lib/user-settings.ts: nieuwe ProductsTablePrefs schema (search, includeArchived, sort enum, sortDir) onder ViewsPrefs.productsTable. Alle velden optional → defaults via component-fallbacks. - __tests__/components/shared/sort-header.test.tsx: 6 tests (label, click-callback, active/inactive classes, custom className, svg-icoon). - 1028 tests groen totaal; geen regressie in Ideas-tests. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
96 lines
2.3 KiB
TypeScript
96 lines
2.3 KiB
TypeScript
// @vitest-environment jsdom
|
|
import { describe, it, expect, vi } from 'vitest'
|
|
import { render, screen, fireEvent } from '@testing-library/react'
|
|
|
|
import { SortHeader } from '@/components/shared/sort-header'
|
|
|
|
type Cols = 'name' | 'date'
|
|
|
|
describe('SortHeader', () => {
|
|
it('rendert label en is een button', () => {
|
|
render(
|
|
<SortHeader<Cols>
|
|
col="name"
|
|
label="Naam"
|
|
sortKey="date"
|
|
sortDir="asc"
|
|
onSort={vi.fn()}
|
|
/>,
|
|
)
|
|
expect(screen.queryByText('Naam')).not.toBeNull()
|
|
expect(screen.getByRole('button')).not.toBeNull()
|
|
})
|
|
|
|
it('roept onSort aan met juiste col bij klik', () => {
|
|
const onSort = vi.fn()
|
|
render(
|
|
<SortHeader<Cols>
|
|
col="name"
|
|
label="Naam"
|
|
sortKey="date"
|
|
sortDir="asc"
|
|
onSort={onSort}
|
|
/>,
|
|
)
|
|
fireEvent.click(screen.getByRole('button'))
|
|
expect(onSort).toHaveBeenCalledWith('name')
|
|
})
|
|
|
|
it('actieve kolom heeft text-foreground class', () => {
|
|
render(
|
|
<SortHeader<Cols>
|
|
col="name"
|
|
label="Naam"
|
|
sortKey="name"
|
|
sortDir="asc"
|
|
onSort={vi.fn()}
|
|
/>,
|
|
)
|
|
const button = screen.getByRole('button')
|
|
expect(button.className).toContain('text-foreground')
|
|
expect(button.className).not.toContain('text-muted-foreground')
|
|
})
|
|
|
|
it('niet-actieve kolom heeft text-muted-foreground class', () => {
|
|
render(
|
|
<SortHeader<Cols>
|
|
col="name"
|
|
label="Naam"
|
|
sortKey="date"
|
|
sortDir="asc"
|
|
onSort={vi.fn()}
|
|
/>,
|
|
)
|
|
const button = screen.getByRole('button')
|
|
expect(button.className).toContain('text-muted-foreground')
|
|
})
|
|
|
|
it('accepteert custom className', () => {
|
|
render(
|
|
<SortHeader<Cols>
|
|
col="name"
|
|
label="Naam"
|
|
sortKey="date"
|
|
sortDir="asc"
|
|
onSort={vi.fn()}
|
|
className="ml-4 custom-class"
|
|
/>,
|
|
)
|
|
const button = screen.getByRole('button')
|
|
expect(button.className).toContain('custom-class')
|
|
expect(button.className).toContain('ml-4')
|
|
})
|
|
|
|
it('rendert een svg-icoon naast het label', () => {
|
|
const { container } = render(
|
|
<SortHeader<Cols>
|
|
col="name"
|
|
label="Naam"
|
|
sortKey="name"
|
|
sortDir="asc"
|
|
onSort={vi.fn()}
|
|
/>,
|
|
)
|
|
expect(container.querySelector('svg')).not.toBeNull()
|
|
})
|
|
})
|