|
1 | 1 | import { describe, expect, it, vi } from 'vitest' |
2 | 2 | import { batch, createAtom } from '@tanstack/store' |
3 | 3 | import { |
| 4 | + columnFilteringFeature, |
4 | 5 | constructTable, |
| 6 | + globalFilteringFeature, |
5 | 7 | rowPaginationFeature, |
6 | 8 | rowSelectionFeature, |
7 | 9 | rowSortingFeature, |
@@ -180,6 +182,71 @@ describe('three-layer atom architecture', () => { |
180 | 182 | }) |
181 | 183 | }) |
182 | 184 |
|
| 185 | + describe('explicitly undefined controlled state (#5909)', () => { |
| 186 | + it('falls back to the slice initial default at construct', () => { |
| 187 | + const table = makeTable({ state: { sorting: undefined } }) |
| 188 | + expect(table.atoms.sorting.get()).toEqual([]) |
| 189 | + expect(table.store.state.sorting).toEqual([]) |
| 190 | + expect(table.baseAtoms.sorting.get()).toEqual([]) |
| 191 | + }) |
| 192 | + |
| 193 | + it('falls back to user-provided initialState', () => { |
| 194 | + const table = makeTable({ |
| 195 | + initialState: { sorting: [{ id: 'name', desc: true }] }, |
| 196 | + state: { sorting: undefined }, |
| 197 | + }) |
| 198 | + expect(table.store.state.sorting).toEqual([{ id: 'name', desc: true }]) |
| 199 | + }) |
| 200 | + |
| 201 | + it('does not poison baseAtoms when a controlled slice becomes undefined', () => { |
| 202 | + const controlled: SortingState = [{ id: 'name', desc: false }] |
| 203 | + const table = makeTable({ state: { sorting: controlled } }) |
| 204 | + const internalTable = table as unknown as Table_Internal< |
| 205 | + typeof features, |
| 206 | + any |
| 207 | + > |
| 208 | + expect(table.baseAtoms.sorting.get()).toBe(controlled) |
| 209 | + |
| 210 | + table_setOptions(internalTable, (options) => ({ |
| 211 | + ...options, |
| 212 | + state: { sorting: undefined }, |
| 213 | + })) |
| 214 | + expect(table.store.state.sorting).toEqual([]) |
| 215 | + expect(table.baseAtoms.sorting.get()).toEqual([]) |
| 216 | + |
| 217 | + // removing the key returns the slice to uncontrolled internal writes |
| 218 | + table_setOptions(internalTable, (options) => ({ |
| 219 | + ...options, |
| 220 | + state: {}, |
| 221 | + })) |
| 222 | + table.setSorting([{ id: 'age', desc: true }]) |
| 223 | + expect(table.store.state.sorting).toEqual([{ id: 'age', desc: true }]) |
| 224 | + }) |
| 225 | + |
| 226 | + it('controlled globalFilter can still be cleared with undefined', () => { |
| 227 | + const gfFeatures = testFeatures({ |
| 228 | + columnFilteringFeature, |
| 229 | + globalFilteringFeature, |
| 230 | + }) |
| 231 | + const table = constructTable({ |
| 232 | + features: gfFeatures, |
| 233 | + columns: [], |
| 234 | + data: [], |
| 235 | + state: { globalFilter: 'search' }, |
| 236 | + }) |
| 237 | + expect(table.store.state.globalFilter).toBe('search') |
| 238 | + |
| 239 | + table_setOptions( |
| 240 | + table as unknown as Table_Internal<typeof gfFeatures, any>, |
| 241 | + (options) => ({ |
| 242 | + ...options, |
| 243 | + state: { globalFilter: undefined }, |
| 244 | + }), |
| 245 | + ) |
| 246 | + expect(table.store.state.globalFilter).toBeUndefined() |
| 247 | + }) |
| 248 | + }) |
| 249 | + |
183 | 250 | describe('store (readonly flat derived)', () => { |
184 | 251 | it('has identical public shape to TableState', () => { |
185 | 252 | const table = makeTable() |
|
0 commit comments