Skip to content

Commit f7baae9

Browse files
adamalstonsojinantony01
authored andcommitted
refactor: rewrite sorting in typescript and add tests (carbon-design-system#19225)
1 parent 25dc5eb commit f7baae9

File tree

3 files changed

+264
-125
lines changed

3 files changed

+264
-125
lines changed

packages/react/src/components/DataTable/tools/__tests__/sorting-test.js

Lines changed: 150 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
/**
2-
* Copyright IBM Corp. 2016, 2023
2+
* Copyright IBM Corp. 2016, 2025
33
*
44
* This source code is licensed under the Apache-2.0 license found in the
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
import { sortRows, defaultSortRow } from '../sorting';
8+
import { compare, defaultSortRow, sortRows } from '../sorting';
99
import { sortStates } from '../../state/sorting';
1010

11-
describe('sortRow', () => {
11+
describe('sortRows', () => {
1212
const rowIds = ['row2', 'row1'];
1313
const cellsById = {
1414
'row1:header1': { value: 'cell11' },
@@ -53,6 +53,91 @@ describe('sortRow', () => {
5353
})
5454
).toEqual(['row2', 'row1']);
5555
});
56+
57+
it('should sort React elements correctly', () => {
58+
const reactCells1 = {
59+
'row1:header1': { value: { props: { children: 'Apple' } } },
60+
'row2:header1': { value: { props: { children: 'Banana' } } },
61+
};
62+
const reactCells2 = {
63+
'row1:header1': { value: { props: { children: 1000 } } },
64+
'row2:header1': { value: { props: { children: 'hmm' } } },
65+
};
66+
67+
expect(
68+
sortRows({
69+
rowIds,
70+
cellsById: reactCells1,
71+
sortDirection: sortStates.ASC,
72+
key: 'header1',
73+
locale: 'en',
74+
sortRow: defaultSortRow,
75+
})
76+
).toEqual(['row1', 'row2']);
77+
expect(
78+
sortRows({
79+
rowIds,
80+
cellsById: reactCells2,
81+
sortDirection: sortStates.ASC,
82+
key: 'header1',
83+
locale: 'en',
84+
sortRow: defaultSortRow,
85+
})
86+
).toEqual(['row2', 'row1']);
87+
});
88+
89+
it('should sort numeric strings as numbers', () => {
90+
const cells = {
91+
'row1:header1': { value: '10' },
92+
'row2:header1': { value: '2' },
93+
};
94+
95+
expect(
96+
sortRows({
97+
rowIds,
98+
cellsById: cells,
99+
sortDirection: sortStates.ASC,
100+
key: 'header1',
101+
locale: 'en',
102+
})
103+
).toEqual(['row2', 'row1']);
104+
});
105+
106+
it('should handle a custom `sortRow` function', () => {
107+
const customSortRow = (a, b) => a.length - b.length;
108+
109+
const customCells = {
110+
'row1:header1': { value: 'short' },
111+
'row2:header1': { value: 'longerstring' },
112+
};
113+
114+
expect(
115+
sortRows({
116+
rowIds,
117+
cellsById: customCells,
118+
sortDirection: sortStates.ASC,
119+
key: 'header1',
120+
sortRow: customSortRow,
121+
})
122+
).toEqual(['row1', 'row2']);
123+
});
124+
125+
it('should maintain order for equal values', () => {
126+
const cells = {
127+
'row1:header1': { value: 'same' },
128+
'row2:header1': { value: 'same' },
129+
};
130+
131+
expect(rowIds).toEqual(['row2', 'row1']);
132+
expect(
133+
sortRows({
134+
rowIds,
135+
cellsById: cells,
136+
sortDirection: sortStates.ASC,
137+
key: 'header1',
138+
})
139+
).toEqual(['row2', 'row1']);
140+
});
56141
});
57142

58143
describe('defaultSortRow', () => {
@@ -76,3 +161,65 @@ describe('defaultSortRow', () => {
76161
expect(defaultSortRow('1', '2', sortProps)).toBeGreaterThan(0);
77162
});
78163
});
164+
165+
describe('compare', () => {
166+
it('should treat null as empty string', () => {
167+
expect(compare(null, 'abc')).toEqual(-1);
168+
expect(compare(null, null)).toEqual(0);
169+
expect(compare('abc', null)).toEqual(1);
170+
});
171+
172+
it('should compare numbers correctly', () => {
173+
expect(compare(10, 5)).toEqual(5);
174+
expect(compare(3, 3)).toEqual(0);
175+
expect(compare(1, 10)).toEqual(-9);
176+
});
177+
178+
it('should compare mixed strings and numbers as strings', () => {
179+
expect(compare('5', 10)).toEqual(-1);
180+
expect(compare(20, '10')).toEqual(1);
181+
});
182+
183+
it('should compare React elements whose `props.children` are strings', () => {
184+
const a = { props: { children: 'Apple' } };
185+
const b = { props: { children: 'Banana' } };
186+
187+
expect(compare(a, b)).toEqual(-1);
188+
});
189+
190+
it('should fallback to string comparison when `props.children` is not a string', () => {
191+
const a = { props: { children: 123 } };
192+
const b = { props: { children: 'banana' } };
193+
194+
expect(compare(a, b)).toEqual(0);
195+
});
196+
197+
it('should fallback to string comparison for non-matching types', () => {
198+
expect(compare({}, 1)).toEqual(-1);
199+
expect(compare(true, 'false')).toEqual(1);
200+
});
201+
202+
it('should treat `undefined` as a string when comparing', () => {
203+
expect(compare(undefined, 'abc')).toEqual(1);
204+
expect(compare(undefined, undefined)).toEqual(0);
205+
expect(compare('abc', undefined)).toEqual(-1);
206+
});
207+
208+
it('should use locale for string comparison', () => {
209+
expect(compare('ä', 'z', 'sv-SE')).toEqual(1);
210+
expect(compare('z', 'ä', 'sv-SE')).toEqual(-1);
211+
expect(compare('ä', 'z', 'en-US')).toEqual(-1);
212+
expect(compare('z', 'ä', 'en-US')).toEqual(1);
213+
expect(compare('ä', 'z', 'de-DE')).toEqual(-1);
214+
expect(compare('z', 'ä', 'de-DE')).toEqual(1);
215+
});
216+
217+
it('should compare falsy values correctly', () => {
218+
expect(compare(false, true)).toEqual(-1);
219+
expect(compare(true, false)).toEqual(1);
220+
expect(compare(0, false)).toEqual(-1);
221+
expect(compare(false, 0)).toEqual(1);
222+
expect(compare(null, undefined)).toEqual(-1);
223+
expect(compare(undefined, null)).toEqual(1);
224+
});
225+
});

packages/react/src/components/DataTable/tools/sorting.js

Lines changed: 0 additions & 122 deletions
This file was deleted.

0 commit comments

Comments
 (0)