Skip to content

Commit 47af44c

Browse files
committed
test: add lots of missing utils tests
1 parent f2ea279 commit 47af44c

17 files changed

Lines changed: 3907 additions & 13 deletions
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { describe, expect, it } from 'vitest'
2+
import { constructTable } from '../../../../src'
3+
import {
4+
cell_getContext,
5+
cell_getValue,
6+
cell_renderValue,
7+
} from '../../../../src/static-functions'
8+
import { testFeatures } from '../../../fixtures/features'
9+
import type { ColumnDef } from '../../../../src'
10+
11+
type Person = {
12+
firstName: string
13+
nickname: string | null
14+
}
15+
16+
const features = testFeatures({})
17+
18+
const columns: Array<ColumnDef<typeof features, Person, any>> = [
19+
{ accessorKey: 'firstName', id: 'firstName' },
20+
{ accessorKey: 'nickname', id: 'nickname' },
21+
]
22+
23+
function makeTable() {
24+
return constructTable<typeof features, Person>({
25+
features,
26+
columns,
27+
data: [{ firstName: 'Tanner', nickname: null }],
28+
renderFallbackValue: 'N/A',
29+
})
30+
}
31+
32+
function getCell(columnId: string) {
33+
const table = makeTable()
34+
const row = table.getRowModel().rows[0]!
35+
return row.getAllCellsByColumnId()[columnId]!
36+
}
37+
38+
describe('cell_getValue', () => {
39+
it('should read the accessor value for the cell', () => {
40+
expect(cell_getValue(getCell('firstName'))).toBe('Tanner')
41+
})
42+
})
43+
44+
describe('cell_renderValue', () => {
45+
it('should return the accessor value when present', () => {
46+
expect(cell_renderValue(getCell('firstName'))).toBe('Tanner')
47+
})
48+
49+
it('should fall back to renderFallbackValue for nullish values', () => {
50+
expect(cell_renderValue(getCell('nickname'))).toBe('N/A')
51+
})
52+
})
53+
54+
describe('cell_getContext', () => {
55+
it('should expose the table, column, row, and cell with bound value helpers', () => {
56+
const table = makeTable()
57+
const row = table.getRowModel().rows[0]!
58+
const cell = row.getAllCellsByColumnId()['firstName']!
59+
60+
const context = cell_getContext(cell)
61+
62+
expect(context.table).toBe(cell.table)
63+
expect(context.column).toBe(cell.column)
64+
expect(context.row).toBe(row)
65+
expect(context.cell).toBe(cell)
66+
expect(context.getValue()).toBe('Tanner')
67+
expect(context.renderValue()).toBe('Tanner')
68+
})
69+
})
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
import { describe, expect, it } from 'vitest'
2+
import { constructTable } from '../../../../src'
3+
import {
4+
column_getFlatColumns,
5+
column_getLeafColumns,
6+
table_getAllColumns,
7+
table_getAllFlatColumns,
8+
table_getAllFlatColumnsById,
9+
table_getAllLeafColumns,
10+
table_getAllLeafColumnsById,
11+
table_getColumn,
12+
table_getDefaultColumnDef,
13+
} from '../../../../src/static-functions'
14+
import { testFeatures } from '../../../fixtures/features'
15+
import type { ColumnDef } from '../../../../src'
16+
17+
type Item = {
18+
a: string
19+
b: string
20+
c: string
21+
}
22+
23+
const features = testFeatures({})
24+
25+
const columns: Array<ColumnDef<typeof features, Item, any>> = [
26+
{
27+
id: 'group',
28+
header: 'Group',
29+
columns: [
30+
{ accessorKey: 'a', id: 'a' },
31+
{ accessorKey: 'b', id: 'b' },
32+
],
33+
},
34+
{ accessorKey: 'c', id: 'c' },
35+
]
36+
37+
const data: Array<Item> = [{ a: 'a1', b: 'b1', c: 'c1' }]
38+
39+
function makeTable() {
40+
return constructTable<typeof features, Item>({
41+
features,
42+
columns,
43+
data,
44+
})
45+
}
46+
47+
describe('table_getAllColumns', () => {
48+
it('should build the nested column tree from column defs', () => {
49+
const table = makeTable()
50+
const allColumns = table_getAllColumns(table)
51+
52+
expect(allColumns.map((column) => column.id)).toEqual(['group', 'c'])
53+
expect(allColumns[0]!.columns.map((column) => column.id)).toEqual([
54+
'a',
55+
'b',
56+
])
57+
expect(allColumns[0]!.columns[0]!.parent?.id).toBe('group')
58+
expect(allColumns[0]!.columns[0]!.depth).toBe(1)
59+
})
60+
})
61+
62+
describe('column_getFlatColumns', () => {
63+
it('should flatten a group column with itself first', () => {
64+
const table = makeTable()
65+
const groupColumn = table.getColumn('group')!
66+
67+
expect(
68+
column_getFlatColumns(groupColumn).map((column) => column.id),
69+
).toEqual(['group', 'a', 'b'])
70+
})
71+
72+
it('should return only itself for a leaf column', () => {
73+
const table = makeTable()
74+
const leafColumn = table.getColumn('c')!
75+
76+
expect(
77+
column_getFlatColumns(leafColumn).map((column) => column.id),
78+
).toEqual(['c'])
79+
})
80+
})
81+
82+
describe('column_getLeafColumns', () => {
83+
it('should return the descendants of a group column', () => {
84+
const table = makeTable()
85+
const groupColumn = table.getColumn('group')!
86+
87+
expect(
88+
column_getLeafColumns(groupColumn).map((column) => column.id),
89+
).toEqual(['a', 'b'])
90+
})
91+
92+
it('should return only itself for a leaf column', () => {
93+
const table = makeTable()
94+
const leafColumn = table.getColumn('c')!
95+
96+
expect(
97+
column_getLeafColumns(leafColumn).map((column) => column.id),
98+
).toEqual(['c'])
99+
})
100+
})
101+
102+
describe('table_getAllFlatColumns / table_getAllFlatColumnsById', () => {
103+
it('should include group and leaf columns', () => {
104+
const table = makeTable()
105+
106+
expect(table_getAllFlatColumns(table).map((column) => column.id)).toEqual([
107+
'group',
108+
'a',
109+
'b',
110+
'c',
111+
])
112+
113+
const byId = table_getAllFlatColumnsById(table)
114+
expect(Object.keys(byId)).toEqual(['group', 'a', 'b', 'c'])
115+
expect(byId['a']!.id).toBe('a')
116+
})
117+
})
118+
119+
describe('table_getAllLeafColumns / table_getAllLeafColumnsById', () => {
120+
it('should exclude group columns', () => {
121+
const table = makeTable()
122+
123+
expect(table_getAllLeafColumns(table).map((column) => column.id)).toEqual([
124+
'a',
125+
'b',
126+
'c',
127+
])
128+
129+
const byId = table_getAllLeafColumnsById(table)
130+
expect(Object.keys(byId)).toEqual(['a', 'b', 'c'])
131+
expect(byId['group']).toBeUndefined()
132+
})
133+
})
134+
135+
describe('table_getColumn', () => {
136+
it('should find group and leaf columns by id', () => {
137+
const table = makeTable()
138+
139+
expect(table_getColumn(table, 'group')?.id).toBe('group')
140+
expect(table_getColumn(table, 'b')?.id).toBe('b')
141+
})
142+
143+
it('should return undefined for unknown column ids', () => {
144+
const table = makeTable()
145+
146+
expect(table_getColumn(table, 'missing')).toBeUndefined()
147+
})
148+
})
149+
150+
describe('table_getDefaultColumnDef', () => {
151+
it('should render accessor keys as the default header', () => {
152+
const table = makeTable()
153+
const defaultColumnDef = table_getDefaultColumnDef(table)
154+
155+
const header = defaultColumnDef.header as (props: any) => unknown
156+
expect(
157+
header({ header: { column: { columnDef: { accessorKey: 'a' } } } }),
158+
).toBe('a')
159+
expect(
160+
header({
161+
header: {
162+
column: { columnDef: { accessorFn: () => 1, id: 'fn-col' } },
163+
},
164+
}),
165+
).toBe('fn-col')
166+
expect(header({ header: { column: { columnDef: {} } } })).toBeNull()
167+
})
168+
169+
it('should stringify values in the default cell renderer', () => {
170+
const table = makeTable()
171+
const defaultColumnDef = table_getDefaultColumnDef(table)
172+
173+
const cell = defaultColumnDef.cell as (props: any) => unknown
174+
expect(cell({ renderValue: () => 42 })).toBe('42')
175+
expect(cell({ renderValue: () => null })).toBeNull()
176+
})
177+
178+
it('should let options.defaultColumn win', () => {
179+
const table = constructTable<typeof features, Item>({
180+
features,
181+
columns,
182+
data,
183+
defaultColumn: { header: 'custom header' },
184+
})
185+
186+
expect(table_getDefaultColumnDef(table).header).toBe('custom header')
187+
})
188+
})
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import { describe, expect, it } from 'vitest'
2+
import {
3+
columnPinningFeature,
4+
columnVisibilityFeature,
5+
constructTable,
6+
} from '../../../../src'
7+
import {
8+
header_getContext,
9+
header_getLeafHeaders,
10+
table_getHeaderGroups,
11+
table_getLeafHeaders,
12+
} from '../../../../src/static-functions'
13+
import { testFeatures } from '../../../fixtures/features'
14+
import type { ColumnDef, Table, TableOptions } from '../../../../src'
15+
16+
type Item = {
17+
a: string
18+
b: string
19+
c: string
20+
}
21+
22+
const features = testFeatures({
23+
columnPinningFeature,
24+
columnVisibilityFeature,
25+
})
26+
27+
const columns: Array<ColumnDef<typeof features, Item, any>> = [
28+
{
29+
id: 'group',
30+
header: 'Group',
31+
columns: [
32+
{ accessorKey: 'a', id: 'a' },
33+
{ accessorKey: 'b', id: 'b' },
34+
],
35+
},
36+
{ accessorKey: 'c', id: 'c' },
37+
]
38+
39+
const data: Array<Item> = [{ a: 'a1', b: 'b1', c: 'c1' }]
40+
41+
function makeTable(
42+
options?: Partial<
43+
Omit<TableOptions<typeof features, Item>, 'data' | 'columns' | 'features'>
44+
>,
45+
): Table<typeof features, Item> {
46+
return constructTable({
47+
features,
48+
columns,
49+
data,
50+
...options,
51+
})
52+
}
53+
54+
describe('table_getHeaderGroups', () => {
55+
it('should build one group per column depth', () => {
56+
const table = makeTable()
57+
const headerGroups = table_getHeaderGroups(table)
58+
59+
expect(headerGroups).toHaveLength(2)
60+
expect(headerGroups[1]!.headers.map((header) => header.column.id)).toEqual([
61+
'a',
62+
'b',
63+
'c',
64+
])
65+
})
66+
67+
it('should order pinned columns first via the pin partitioning path', () => {
68+
const table = makeTable({
69+
initialState: { columnPinning: { left: ['c'], right: [] } },
70+
})
71+
const headerGroups = table_getHeaderGroups(table)
72+
73+
expect(headerGroups[1]!.headers.map((header) => header.column.id)).toEqual([
74+
'c',
75+
'a',
76+
'b',
77+
])
78+
})
79+
80+
it('should exclude hidden columns', () => {
81+
const table = makeTable({
82+
initialState: { columnVisibility: { b: false } },
83+
})
84+
const headerGroups = table_getHeaderGroups(table)
85+
86+
expect(headerGroups[1]!.headers.map((header) => header.column.id)).toEqual([
87+
'a',
88+
'c',
89+
])
90+
})
91+
})
92+
93+
describe('header_getLeafHeaders', () => {
94+
it('should collect descendant leaf headers before the header itself', () => {
95+
const table = makeTable()
96+
const groupHeader = table_getHeaderGroups(table)[0]!.headers.find(
97+
(header) => header.column.id === 'group',
98+
)!
99+
100+
const leafHeaders = header_getLeafHeaders(groupHeader)
101+
102+
expect(leafHeaders.map((header) => header.column.id)).toEqual([
103+
'a',
104+
'b',
105+
'group',
106+
])
107+
})
108+
109+
it('should return only itself for a leaf header', () => {
110+
const table = makeTable()
111+
const leafHeader = table_getHeaderGroups(table)[1]!.headers.find(
112+
(header) => header.column.id === 'a',
113+
)!
114+
115+
expect(header_getLeafHeaders(leafHeader)).toEqual([leafHeader])
116+
})
117+
})
118+
119+
describe('header_getContext', () => {
120+
it('should expose the header, column, and table', () => {
121+
const table = makeTable()
122+
const header = table_getHeaderGroups(table)[1]!.headers[0]!
123+
124+
const context = header_getContext(header)
125+
126+
expect(context.header).toBe(header)
127+
expect(context.column).toBe(header.column)
128+
expect(context.table).toBe(header.column.table)
129+
})
130+
})
131+
132+
describe('table_getLeafHeaders', () => {
133+
it('should collect the leaf headers reachable from the top header row', () => {
134+
const table = makeTable()
135+
const ids = table_getLeafHeaders(table).map((header) => header.column.id)
136+
137+
expect(ids).toEqual(expect.arrayContaining(['a', 'b', 'c']))
138+
})
139+
})

0 commit comments

Comments
 (0)