diff --git a/packages/table-core/src/features/row-sorting/createSortedRowModel.ts b/packages/table-core/src/features/row-sorting/createSortedRowModel.ts index a363fb7bc6..6c948ca349 100644 --- a/packages/table-core/src/features/row-sorting/createSortedRowModel.ts +++ b/packages/table-core/src/features/row-sorting/createSortedRowModel.ts @@ -51,11 +51,10 @@ function _createSortedRowModel< const sortedFlatRows: Array> = [] // Filter out sortings that correspond to non existing columns - const availableSorting = sorting.filter((sort) => - column_getCanSort( - table.getColumn(sort.id) as Column_Internal, - ), - ) + const availableSorting = sorting.filter((sort) => { + const column = table.getColumn(sort.id) + return column ? column_getCanSort(column) : false + }) const resolvedSorting: Array<{ id: string diff --git a/packages/table-core/tests/unit/features/row-sorting/createSortedRowModel.test.ts b/packages/table-core/tests/unit/features/row-sorting/createSortedRowModel.test.ts new file mode 100644 index 0000000000..e3ee25aad8 --- /dev/null +++ b/packages/table-core/tests/unit/features/row-sorting/createSortedRowModel.test.ts @@ -0,0 +1,71 @@ +import { describe, expect, it } from 'vitest' +import { + constructTable, + coreFeatures, + createSortedRowModel, + rowSortingFeature, + tableFeatures, +} from '../../../../src' +import { storeReactivityBindings } from '../../../../src/store-reactivity-bindings' +import type { ColumnDef } from '../../../../src' + +type Person = { + firstName: string + age: number +} + +const features = tableFeatures({ + ...coreFeatures, + rowSortingFeature, + sortedRowModel: createSortedRowModel(), +}) + +const columns: Array> = [ + { accessorKey: 'firstName', id: 'firstName' }, + { accessorKey: 'age', id: 'age' }, +] + +const data: Array = [ + { firstName: 'amy', age: 20 }, + { firstName: 'bob', age: 40 }, + { firstName: 'alice', age: 30 }, +] + +function makeTable(sorting: Array<{ id: string; desc: boolean }>) { + return constructTable({ + data, + columns, + features: { + ...features, + coreReactivityFeature: storeReactivityBindings(), + }, + initialState: { sorting }, + }) +} + +describe('createSortedRowModel', () => { + it('does not crash when the sorting state references a column that no longer exists', () => { + const table = makeTable([{ id: 'thisColumnDoesNotExist', desc: false }]) + + expect(() => table.getSortedRowModel()).not.toThrow() + }) + + it('falls back to the pre-sorted row order when only unknown columns are sorted', () => { + const table = makeTable([{ id: 'thisColumnDoesNotExist', desc: false }]) + + expect( + table.getSortedRowModel().rows.map((row) => row.original.firstName), + ).toEqual(['amy', 'bob', 'alice']) + }) + + it('still sorts by the remaining known columns when one sort entry is unknown', () => { + const table = makeTable([ + { id: 'thisColumnDoesNotExist', desc: false }, + { id: 'age', desc: false }, + ]) + + expect( + table.getSortedRowModel().rows.map((row) => row.original.firstName), + ).toEqual(['amy', 'alice', 'bob']) + }) +})