@powerhousedao/document-engineering 1.39.0 → 1.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +12 -0
  2. package/dist/src/table/components/default-fns/default-cell-on-save.d.ts +11 -0
  3. package/dist/src/table/components/default-fns/default-cell-on-save.d.ts.map +1 -0
  4. package/dist/src/table/components/default-fns/default-cell-on-save.js +18 -0
  5. package/dist/src/table/components/default-fns/default-cell-on-save.js.map +1 -0
  6. package/dist/src/table/table/object-set-table.d.ts.map +1 -1
  7. package/dist/src/table/table/object-set-table.js +2 -11
  8. package/dist/src/table/table/object-set-table.js.map +1 -1
  9. package/dist/src/table/tests/basic-rendering.test.d.ts +2 -0
  10. package/dist/src/table/tests/basic-rendering.test.d.ts.map +1 -0
  11. package/dist/src/table/tests/basic-rendering.test.js +332 -0
  12. package/dist/src/table/tests/basic-rendering.test.js.map +1 -0
  13. package/dist/src/table/tests/cell-selection.test.d.ts +2 -0
  14. package/dist/src/table/tests/cell-selection.test.d.ts.map +1 -0
  15. package/dist/src/table/tests/cell-selection.test.js +346 -0
  16. package/dist/src/table/tests/cell-selection.test.js.map +1 -0
  17. package/dist/src/table/tests/helpers/test-utils.d.ts +28 -0
  18. package/dist/src/table/tests/helpers/test-utils.d.ts.map +1 -0
  19. package/dist/src/table/tests/helpers/test-utils.js +85 -0
  20. package/dist/src/table/tests/helpers/test-utils.js.map +1 -0
  21. package/dist/src/table/tests/page-objects/base-table.page.d.ts +83 -0
  22. package/dist/src/table/tests/page-objects/base-table.page.d.ts.map +1 -0
  23. package/dist/src/table/tests/page-objects/base-table.page.js +146 -0
  24. package/dist/src/table/tests/page-objects/base-table.page.js.map +1 -0
  25. package/dist/src/table/tests/page-objects/table-cell.page.d.ts +58 -0
  26. package/dist/src/table/tests/page-objects/table-cell.page.d.ts.map +1 -0
  27. package/dist/src/table/tests/page-objects/table-cell.page.js +163 -0
  28. package/dist/src/table/tests/page-objects/table-cell.page.js.map +1 -0
  29. package/dist/src/table/tests/page-objects/table-header.page.d.ts +66 -0
  30. package/dist/src/table/tests/page-objects/table-header.page.d.ts.map +1 -0
  31. package/dist/src/table/tests/page-objects/table-header.page.js +156 -0
  32. package/dist/src/table/tests/page-objects/table-header.page.js.map +1 -0
  33. package/dist/src/table/tests/page-objects/table-row.page.d.ts +98 -0
  34. package/dist/src/table/tests/page-objects/table-row.page.d.ts.map +1 -0
  35. package/dist/src/table/tests/page-objects/table-row.page.js +240 -0
  36. package/dist/src/table/tests/page-objects/table-row.page.js.map +1 -0
  37. package/dist/src/table/tests/page-objects/table.page.d.ts +36 -0
  38. package/dist/src/table/tests/page-objects/table.page.d.ts.map +1 -0
  39. package/dist/src/table/tests/page-objects/table.page.js +46 -0
  40. package/dist/src/table/tests/page-objects/table.page.js.map +1 -0
  41. package/dist/src/table/tests/row-actions.test.d.ts +2 -0
  42. package/dist/src/table/tests/row-actions.test.d.ts.map +1 -0
  43. package/dist/src/table/tests/row-actions.test.js +601 -0
  44. package/dist/src/table/tests/row-actions.test.js.map +1 -0
  45. package/dist/src/table/tests/row-selection.test.d.ts +2 -0
  46. package/dist/src/table/tests/row-selection.test.d.ts.map +1 -0
  47. package/dist/src/table/tests/row-selection.test.js +272 -0
  48. package/dist/src/table/tests/row-selection.test.js.map +1 -0
  49. package/dist/src/table/tests/sorting.test.d.ts +2 -0
  50. package/dist/src/table/tests/sorting.test.d.ts.map +1 -0
  51. package/dist/src/table/tests/sorting.test.js +793 -0
  52. package/dist/src/table/tests/sorting.test.js.map +1 -0
  53. package/dist/src/ui/components/data-entry/date-picker/date-picker.js +1 -1
  54. package/dist/src/ui/components/data-entry/date-picker/date-picker.js.map +1 -1
  55. package/dist/style.css +4 -5
  56. package/dist/tsconfig.tsbuildinfo +1 -1
  57. package/package.json +1 -1
@@ -0,0 +1,793 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-call */
2
+ import { describe, expect, it } from 'vitest';
3
+ import { fireEvent } from '@testing-library/react';
4
+ import { createMockPerson, createTestTableConfig, renderTestTable } from './helpers/test-utils.js';
5
+ import { TablePage } from './page-objects/table.page.js';
6
+ describe('ObjectSetTable - Sorting', () => {
7
+ describe('Basic Sorting Functionality', () => {
8
+ it('should sort string column in ascending order', () => {
9
+ const sortableConfig = createTestTableConfig({
10
+ columns: [
11
+ {
12
+ field: 'firstName',
13
+ title: 'First Name',
14
+ type: 'string',
15
+ sortable: true,
16
+ },
17
+ {
18
+ field: 'status',
19
+ title: 'Status',
20
+ type: 'string',
21
+ sortable: true,
22
+ },
23
+ {
24
+ field: 'payment',
25
+ title: 'Payment',
26
+ type: 'number',
27
+ sortable: true,
28
+ },
29
+ ],
30
+ });
31
+ const renderResult = renderTestTable(sortableConfig);
32
+ const table = new TablePage(renderResult);
33
+ // Verify initial state - no sorting
34
+ expect(table.header.isColumnSorted(0)).toBe(false);
35
+ expect(table.header.getColumnSortDirection(0)).toBe(null);
36
+ // Click header to sort ascending (column 1 is First Name, column 0 is row number)
37
+ const headerCell = table.getHeaderCellByIndex(1);
38
+ expect(headerCell).toBeTruthy();
39
+ fireEvent.click(headerCell);
40
+ // Verify sorting state
41
+ expect(table.header.isColumnSorted(1)).toBe(true);
42
+ expect(table.header.getColumnSortDirection(1)).toBe('asc');
43
+ // Verify data is sorted alphabetically (column 1 is First Name)
44
+ expect(table.cell.getCellValue(0, 1)).toBe('Alex');
45
+ expect(table.cell.getCellValue(1, 1)).toBe('Alice');
46
+ expect(table.cell.getCellValue(2, 1)).toBe('Bob');
47
+ expect(table.cell.getCellValue(3, 1)).toBe('Diana');
48
+ expect(table.cell.getCellValue(4, 1)).toBe('Fiona');
49
+ });
50
+ it('should sort string column in descending order', () => {
51
+ const sortableConfig = createTestTableConfig({
52
+ columns: [
53
+ {
54
+ field: 'firstName',
55
+ title: 'First Name',
56
+ type: 'string',
57
+ sortable: true,
58
+ },
59
+ {
60
+ field: 'status',
61
+ title: 'Status',
62
+ type: 'string',
63
+ sortable: true,
64
+ },
65
+ {
66
+ field: 'payment',
67
+ title: 'Payment',
68
+ type: 'number',
69
+ sortable: true,
70
+ },
71
+ ],
72
+ });
73
+ const renderResult = renderTestTable(sortableConfig);
74
+ const table = new TablePage(renderResult);
75
+ // Click header twice to get descending order (column 1 is First Name)
76
+ const headerCell = table.getHeaderCellByIndex(1);
77
+ expect(headerCell).toBeTruthy();
78
+ fireEvent.click(headerCell); // First click: asc
79
+ fireEvent.click(headerCell); // Second click: desc
80
+ // Verify sorting state
81
+ expect(table.header.isColumnSorted(1)).toBe(true);
82
+ expect(table.header.getColumnSortDirection(1)).toBe('desc');
83
+ // Verify data is sorted in descending order (column 1 is First Name)
84
+ expect(table.cell.getCellValue(0, 1)).toBe('Fiona');
85
+ expect(table.cell.getCellValue(1, 1)).toBe('Diana');
86
+ expect(table.cell.getCellValue(2, 1)).toBe('Bob');
87
+ expect(table.cell.getCellValue(3, 1)).toBe('Alice');
88
+ expect(table.cell.getCellValue(4, 1)).toBe('Alex');
89
+ });
90
+ it('should clear sorting on third click', () => {
91
+ const sortableConfig = createTestTableConfig({
92
+ columns: [
93
+ {
94
+ field: 'firstName',
95
+ title: 'First Name',
96
+ type: 'string',
97
+ sortable: true,
98
+ },
99
+ {
100
+ field: 'status',
101
+ title: 'Status',
102
+ type: 'string',
103
+ sortable: true,
104
+ },
105
+ {
106
+ field: 'payment',
107
+ title: 'Payment',
108
+ type: 'number',
109
+ sortable: true,
110
+ },
111
+ ],
112
+ });
113
+ const renderResult = renderTestTable(sortableConfig);
114
+ const table = new TablePage(renderResult);
115
+ // Get original order (column 1 is First Name)
116
+ const originalOrder = table.cell.getColumnCells(1);
117
+ // Click header three times to cycle through: asc -> desc -> none (column 1 is First Name)
118
+ const headerCell = table.getHeaderCellByIndex(1);
119
+ expect(headerCell).toBeTruthy();
120
+ fireEvent.click(headerCell); // First click: asc
121
+ fireEvent.click(headerCell); // Second click: desc
122
+ fireEvent.click(headerCell); // Third click: none
123
+ // Verify sorting is cleared
124
+ expect(table.header.isColumnSorted(1)).toBe(false);
125
+ expect(table.header.getColumnSortDirection(1)).toBe(null);
126
+ // Verify data is back to original order (column 1 is First Name)
127
+ const currentOrder = table.cell.getColumnCells(1);
128
+ expect(currentOrder).toEqual(originalOrder);
129
+ });
130
+ it('should sort numeric column correctly', () => {
131
+ const sortableConfig = createTestTableConfig({
132
+ columns: [
133
+ {
134
+ field: 'firstName',
135
+ title: 'First Name',
136
+ type: 'string',
137
+ sortable: true,
138
+ },
139
+ {
140
+ field: 'payment',
141
+ title: 'Payment',
142
+ type: 'number',
143
+ sortable: true,
144
+ },
145
+ ],
146
+ });
147
+ const renderResult = renderTestTable(sortableConfig);
148
+ const table = new TablePage(renderResult);
149
+ // Click payment column header to sort ascending (column 2 is Payment)
150
+ const paymentHeaderCell = table.getHeaderCellByIndex(2);
151
+ expect(paymentHeaderCell).toBeTruthy();
152
+ fireEvent.click(paymentHeaderCell);
153
+ // Verify sorting state
154
+ expect(table.header.isColumnSorted(2)).toBe(true);
155
+ expect(table.header.getColumnSortDirection(2)).toBe('asc');
156
+ // Verify numeric data is sorted correctly (column 2 is Payment)
157
+ expect(table.cell.getCellValue(0, 2)).toBe('0');
158
+ expect(table.cell.getCellValue(1, 2)).toBe('15');
159
+ expect(table.cell.getCellValue(2, 2)).toBe('100');
160
+ expect(table.cell.getCellValue(3, 2)).toBe('14522');
161
+ expect(table.cell.getCellValue(4, 2)).toBe('1065460');
162
+ });
163
+ it('should sort numeric column in descending order', () => {
164
+ const sortableConfig = createTestTableConfig({
165
+ columns: [
166
+ {
167
+ field: 'firstName',
168
+ title: 'First Name',
169
+ type: 'string',
170
+ sortable: true,
171
+ },
172
+ {
173
+ field: 'payment',
174
+ title: 'Payment',
175
+ type: 'number',
176
+ sortable: true,
177
+ },
178
+ ],
179
+ });
180
+ const renderResult = renderTestTable(sortableConfig);
181
+ const table = new TablePage(renderResult);
182
+ // Click payment column header twice to sort descending (column 2 is Payment)
183
+ const paymentHeaderCell = table.getHeaderCellByIndex(2);
184
+ expect(paymentHeaderCell).toBeTruthy();
185
+ fireEvent.click(paymentHeaderCell); // First click: asc
186
+ fireEvent.click(paymentHeaderCell); // Second click: desc
187
+ // Verify sorting state
188
+ expect(table.header.isColumnSorted(2)).toBe(true);
189
+ expect(table.header.getColumnSortDirection(2)).toBe('desc');
190
+ // Verify numeric data is sorted in descending order (column 2 is Payment)
191
+ expect(table.cell.getCellValue(0, 2)).toBe('10234234230');
192
+ expect(table.cell.getCellValue(1, 2)).toBe('11231200');
193
+ expect(table.cell.getCellValue(2, 2)).toBe('1065460');
194
+ expect(table.cell.getCellValue(3, 2)).toBe('14522');
195
+ expect(table.cell.getCellValue(4, 2)).toBe('100');
196
+ });
197
+ });
198
+ describe('Sorting State Management', () => {
199
+ it('should switch sorting to different column', () => {
200
+ const sortableConfig = createTestTableConfig({
201
+ columns: [
202
+ {
203
+ field: 'firstName',
204
+ title: 'First Name',
205
+ type: 'string',
206
+ sortable: true,
207
+ },
208
+ {
209
+ field: 'status',
210
+ title: 'Status',
211
+ type: 'string',
212
+ sortable: true,
213
+ },
214
+ {
215
+ field: 'payment',
216
+ title: 'Payment',
217
+ type: 'number',
218
+ sortable: true,
219
+ },
220
+ ],
221
+ });
222
+ const renderResult = renderTestTable(sortableConfig);
223
+ const table = new TablePage(renderResult);
224
+ // Sort by firstName column (column 1 is First Name)
225
+ const firstNameHeader = table.getHeaderCellByIndex(1);
226
+ expect(firstNameHeader).toBeTruthy();
227
+ fireEvent.click(firstNameHeader);
228
+ // Verify firstName is sorted
229
+ expect(table.header.isColumnSorted(1)).toBe(true);
230
+ expect(table.header.getColumnSortDirection(1)).toBe('asc');
231
+ expect(table.header.isColumnSorted(2)).toBe(false);
232
+ // Sort by status column (column 2 is Status)
233
+ const statusHeader = table.getHeaderCellByIndex(2);
234
+ expect(statusHeader).toBeTruthy();
235
+ fireEvent.click(statusHeader);
236
+ // Verify status is now sorted and firstName is not
237
+ expect(table.header.isColumnSorted(1)).toBe(false);
238
+ expect(table.header.isColumnSorted(2)).toBe(true);
239
+ expect(table.header.getColumnSortDirection(2)).toBe('asc');
240
+ });
241
+ it('should maintain sort direction when switching columns', () => {
242
+ const sortableConfig = createTestTableConfig({
243
+ columns: [
244
+ {
245
+ field: 'firstName',
246
+ title: 'First Name',
247
+ type: 'string',
248
+ sortable: true,
249
+ },
250
+ {
251
+ field: 'status',
252
+ title: 'Status',
253
+ type: 'string',
254
+ sortable: true,
255
+ },
256
+ {
257
+ field: 'payment',
258
+ title: 'Payment',
259
+ type: 'number',
260
+ sortable: true,
261
+ },
262
+ ],
263
+ });
264
+ const renderResult = renderTestTable(sortableConfig);
265
+ const table = new TablePage(renderResult);
266
+ // Sort firstName column to descending (column 1 is First Name)
267
+ const firstNameHeader = table.getHeaderCellByIndex(1);
268
+ expect(firstNameHeader).toBeTruthy();
269
+ fireEvent.click(firstNameHeader); // asc
270
+ fireEvent.click(firstNameHeader); // desc
271
+ // Verify firstName is sorted descending
272
+ expect(table.header.isColumnSorted(1)).toBe(true);
273
+ expect(table.header.getColumnSortDirection(1)).toBe('desc');
274
+ // Switch to status column (column 2 is Status)
275
+ const statusHeader = table.getHeaderCellByIndex(2);
276
+ expect(statusHeader).toBeTruthy();
277
+ fireEvent.click(statusHeader);
278
+ // Verify status is sorted ascending (new column starts with asc)
279
+ expect(table.header.isColumnSorted(1)).toBe(false);
280
+ expect(table.header.isColumnSorted(2)).toBe(true);
281
+ expect(table.header.getColumnSortDirection(2)).toBe('asc');
282
+ });
283
+ it('should handle multiple column sorting interactions', () => {
284
+ const sortableConfig = createTestTableConfig({
285
+ columns: [
286
+ {
287
+ field: 'firstName',
288
+ title: 'First Name',
289
+ type: 'string',
290
+ sortable: true,
291
+ },
292
+ {
293
+ field: 'status',
294
+ title: 'Status',
295
+ type: 'string',
296
+ sortable: true,
297
+ },
298
+ {
299
+ field: 'payment',
300
+ title: 'Payment',
301
+ type: 'number',
302
+ sortable: true,
303
+ },
304
+ ],
305
+ });
306
+ const renderResult = renderTestTable(sortableConfig);
307
+ const table = new TablePage(renderResult);
308
+ // Sort by firstName (column 1 is First Name)
309
+ const firstNameHeader = table.getHeaderCellByIndex(1);
310
+ expect(firstNameHeader).toBeTruthy();
311
+ fireEvent.click(firstNameHeader);
312
+ expect(table.header.getColumnSortDirection(1)).toBe('asc');
313
+ // Sort by payment (column 3 is Payment)
314
+ const paymentHeader = table.getHeaderCellByIndex(3);
315
+ expect(paymentHeader).toBeTruthy();
316
+ fireEvent.click(paymentHeader);
317
+ expect(table.header.getColumnSortDirection(3)).toBe('asc');
318
+ expect(table.header.isColumnSorted(1)).toBe(false);
319
+ // Sort by status (column 2 is Status)
320
+ const statusHeader = table.getHeaderCellByIndex(2);
321
+ expect(statusHeader).toBeTruthy();
322
+ fireEvent.click(statusHeader);
323
+ expect(table.header.getColumnSortDirection(2)).toBe('asc');
324
+ expect(table.header.isColumnSorted(3)).toBe(false);
325
+ });
326
+ });
327
+ describe('Non-Sortable Columns', () => {
328
+ it('should not sort non-sortable columns', () => {
329
+ const mixedConfig = createTestTableConfig({
330
+ columns: [
331
+ {
332
+ field: 'firstName',
333
+ title: 'First Name',
334
+ type: 'string',
335
+ sortable: false,
336
+ },
337
+ {
338
+ field: 'status',
339
+ title: 'Status',
340
+ type: 'string',
341
+ sortable: true,
342
+ },
343
+ {
344
+ field: 'payment',
345
+ title: 'Payment',
346
+ type: 'number',
347
+ sortable: false,
348
+ },
349
+ ],
350
+ });
351
+ const renderResult = renderTestTable(mixedConfig);
352
+ const table = new TablePage(renderResult);
353
+ // Verify firstName column is not sortable (column 1 is First Name)
354
+ expect(table.header.isColumnSortable(1)).toBe(false);
355
+ expect(table.header.isColumnSorted(1)).toBe(false);
356
+ // Verify status column is sortable (column 2 is Status)
357
+ expect(table.header.isColumnSortable(2)).toBe(true);
358
+ // Try to click non-sortable column - should not change sorting
359
+ const firstNameHeader = table.getHeaderCellByIndex(1);
360
+ expect(firstNameHeader).toBeTruthy();
361
+ fireEvent.click(firstNameHeader);
362
+ // Verify no sorting occurred
363
+ expect(table.header.isColumnSorted(1)).toBe(false);
364
+ expect(table.header.getColumnSortDirection(1)).toBe(null);
365
+ });
366
+ it('should only allow sorting on sortable columns', () => {
367
+ const sortableConfig = createTestTableConfig({
368
+ columns: [
369
+ {
370
+ field: 'firstName',
371
+ title: 'First Name',
372
+ type: 'string',
373
+ sortable: true,
374
+ },
375
+ {
376
+ field: 'status',
377
+ title: 'Status',
378
+ type: 'string',
379
+ sortable: false,
380
+ },
381
+ {
382
+ field: 'payment',
383
+ title: 'Payment',
384
+ type: 'number',
385
+ sortable: true,
386
+ },
387
+ ],
388
+ });
389
+ const renderResult = renderTestTable(sortableConfig);
390
+ const table = new TablePage(renderResult);
391
+ // Verify sortable columns
392
+ expect(table.header.isColumnSortable(1)).toBe(true); // firstName
393
+ expect(table.header.isColumnSortable(2)).toBe(false); // status
394
+ expect(table.header.isColumnSortable(3)).toBe(true); // payment
395
+ // Sort by sortable column
396
+ const firstNameHeader = table.getHeaderCellByIndex(1);
397
+ expect(firstNameHeader).toBeTruthy();
398
+ fireEvent.click(firstNameHeader);
399
+ expect(table.header.isColumnSorted(1)).toBe(true);
400
+ // Try to sort non-sortable column
401
+ const statusHeader = table.getHeaderCellByIndex(2);
402
+ expect(statusHeader).toBeTruthy();
403
+ fireEvent.click(statusHeader);
404
+ // Verify firstName is still sorted
405
+ expect(table.header.isColumnSorted(1)).toBe(true);
406
+ expect(table.header.isColumnSorted(2)).toBe(false);
407
+ });
408
+ });
409
+ describe('Null and Empty Value Handling', () => {
410
+ it('should handle null values in sortable columns', () => {
411
+ const sortableConfig = createTestTableConfig({
412
+ columns: [
413
+ {
414
+ field: 'firstName',
415
+ title: 'First Name',
416
+ type: 'string',
417
+ sortable: true,
418
+ },
419
+ {
420
+ field: 'status',
421
+ title: 'Status',
422
+ type: 'string',
423
+ sortable: true,
424
+ },
425
+ ],
426
+ });
427
+ const renderResult = renderTestTable(sortableConfig);
428
+ const table = new TablePage(renderResult);
429
+ // Sort firstName column ascending (column 1 is First Name)
430
+ const firstNameHeader = table.getHeaderCellByIndex(1);
431
+ expect(firstNameHeader).toBeTruthy();
432
+ fireEvent.click(firstNameHeader);
433
+ // Verify null values are placed at the end
434
+ const firstNameValues = table.cell.getColumnCells(1);
435
+ const nullValueIndices = firstNameValues
436
+ .map((value, index) => (value === '' ? index : -1))
437
+ .filter((index) => index !== -1);
438
+ // Null values should be at the end
439
+ expect(nullValueIndices.length).toBeGreaterThan(0);
440
+ const maxNullIndex = Math.max(...nullValueIndices);
441
+ const minNonNullIndex = Math.min(...firstNameValues
442
+ .map((value, index) => (value !== '' ? index : Infinity))
443
+ .filter((index) => index !== Infinity));
444
+ expect(maxNullIndex).toBeGreaterThan(minNonNullIndex);
445
+ });
446
+ it('should handle empty strings in sortable columns', () => {
447
+ const customData = [
448
+ createMockPerson({ firstName: 'Alice' }),
449
+ createMockPerson({ firstName: '' }),
450
+ createMockPerson({ firstName: 'Bob' }),
451
+ createMockPerson({ firstName: null }),
452
+ createMockPerson({ firstName: 'Charlie' }),
453
+ ];
454
+ const sortableConfig = createTestTableConfig({
455
+ columns: [
456
+ {
457
+ field: 'firstName',
458
+ title: 'First Name',
459
+ type: 'string',
460
+ sortable: true,
461
+ },
462
+ ],
463
+ data: customData,
464
+ });
465
+ const renderResult = renderTestTable(sortableConfig);
466
+ const table = new TablePage(renderResult);
467
+ // Sort firstName column ascending (column 1 is First Name)
468
+ const firstNameHeader = table.getHeaderCellByIndex(1);
469
+ expect(firstNameHeader).toBeTruthy();
470
+ fireEvent.click(firstNameHeader);
471
+ // Verify empty and null values are handled correctly
472
+ const firstNameValues = table.cell.getColumnCells(1);
473
+ // Empty strings are placed at the beginning when sorting ascending
474
+ expect(firstNameValues[0]).toBe('');
475
+ expect(firstNameValues[1]).toBe('Alice');
476
+ expect(firstNameValues[2]).toBe('Bob');
477
+ expect(firstNameValues[3]).toBe('Charlie');
478
+ expect(firstNameValues[4]).toBe('');
479
+ });
480
+ });
481
+ describe('Custom Sorting Configuration', () => {
482
+ it('should work with custom sortable configuration', () => {
483
+ const customSortableConfig = createTestTableConfig({
484
+ columns: [
485
+ {
486
+ field: 'firstName',
487
+ title: 'First Name',
488
+ type: 'string',
489
+ sortable: true,
490
+ },
491
+ {
492
+ field: 'status',
493
+ title: 'Status',
494
+ type: 'string',
495
+ sortable: true,
496
+ },
497
+ {
498
+ field: 'payment',
499
+ title: 'Payment',
500
+ type: 'number',
501
+ sortable: true,
502
+ },
503
+ ],
504
+ });
505
+ const renderResult = renderTestTable(customSortableConfig);
506
+ const table = new TablePage(renderResult);
507
+ // Verify all columns are sortable
508
+ expect(table.header.isColumnSortable(1)).toBe(true); // firstName
509
+ expect(table.header.isColumnSortable(2)).toBe(true); // status
510
+ expect(table.header.isColumnSortable(3)).toBe(true); // payment
511
+ // Test sorting each column
512
+ const firstNameHeader = table.getHeaderCellByIndex(1);
513
+ expect(firstNameHeader).toBeTruthy();
514
+ fireEvent.click(firstNameHeader);
515
+ expect(table.header.getColumnSortDirection(1)).toBe('asc');
516
+ const statusHeader = table.getHeaderCellByIndex(2);
517
+ expect(statusHeader).toBeTruthy();
518
+ fireEvent.click(statusHeader);
519
+ expect(table.header.getColumnSortDirection(2)).toBe('asc');
520
+ expect(table.header.isColumnSorted(1)).toBe(false);
521
+ const paymentHeader = table.getHeaderCellByIndex(3);
522
+ expect(paymentHeader).toBeTruthy();
523
+ fireEvent.click(paymentHeader);
524
+ expect(table.header.getColumnSortDirection(3)).toBe('asc');
525
+ expect(table.header.isColumnSorted(2)).toBe(false);
526
+ });
527
+ it('should handle mixed sortable and non-sortable columns', () => {
528
+ const mixedConfig = createTestTableConfig({
529
+ columns: [
530
+ {
531
+ field: 'firstName',
532
+ title: 'First Name',
533
+ type: 'string',
534
+ sortable: true,
535
+ },
536
+ {
537
+ field: 'status',
538
+ title: 'Status',
539
+ type: 'string',
540
+ sortable: false,
541
+ },
542
+ {
543
+ field: 'payment',
544
+ title: 'Payment',
545
+ type: 'number',
546
+ sortable: true,
547
+ },
548
+ {
549
+ field: 'email',
550
+ title: 'Email',
551
+ type: 'string',
552
+ sortable: false,
553
+ },
554
+ ],
555
+ });
556
+ const renderResult = renderTestTable(mixedConfig);
557
+ const table = new TablePage(renderResult);
558
+ // Verify sortable columns
559
+ expect(table.header.isColumnSortable(1)).toBe(true); // firstName
560
+ expect(table.header.isColumnSortable(2)).toBe(false); // status
561
+ expect(table.header.isColumnSortable(3)).toBe(true); // payment
562
+ expect(table.header.isColumnSortable(4)).toBe(false); // email
563
+ // Sort by sortable columns only
564
+ const firstNameHeader = table.getHeaderCellByIndex(1);
565
+ expect(firstNameHeader).toBeTruthy();
566
+ fireEvent.click(firstNameHeader);
567
+ expect(table.header.isColumnSorted(1)).toBe(true);
568
+ const paymentHeader = table.getHeaderCellByIndex(3);
569
+ expect(paymentHeader).toBeTruthy();
570
+ fireEvent.click(paymentHeader);
571
+ expect(table.header.isColumnSorted(3)).toBe(true);
572
+ expect(table.header.isColumnSorted(1)).toBe(false);
573
+ });
574
+ });
575
+ describe('Edge Cases', () => {
576
+ it('should handle sorting with single row', () => {
577
+ const singleRowData = [createMockPerson({ firstName: 'Single User' })];
578
+ const sortableConfig = createTestTableConfig({
579
+ columns: [
580
+ {
581
+ field: 'firstName',
582
+ title: 'First Name',
583
+ type: 'string',
584
+ sortable: true,
585
+ },
586
+ {
587
+ field: 'payment',
588
+ title: 'Payment',
589
+ type: 'number',
590
+ sortable: true,
591
+ },
592
+ ],
593
+ data: singleRowData,
594
+ });
595
+ const renderResult = renderTestTable(sortableConfig);
596
+ const table = new TablePage(renderResult);
597
+ // Sort by firstName (column 1 is First Name)
598
+ const firstNameHeader = table.getHeaderCellByIndex(1);
599
+ expect(firstNameHeader).toBeTruthy();
600
+ fireEvent.click(firstNameHeader);
601
+ // Verify sorting works with single row
602
+ expect(table.header.isColumnSorted(1)).toBe(true);
603
+ expect(table.header.getColumnSortDirection(1)).toBe('asc');
604
+ expect(table.cell.getCellValue(0, 1)).toBe('Single User');
605
+ });
606
+ it('should handle sorting with empty data', () => {
607
+ const sortableConfig = createTestTableConfig({
608
+ columns: [
609
+ {
610
+ field: 'firstName',
611
+ title: 'First Name',
612
+ type: 'string',
613
+ sortable: true,
614
+ },
615
+ {
616
+ field: 'payment',
617
+ title: 'Payment',
618
+ type: 'number',
619
+ sortable: true,
620
+ },
621
+ ],
622
+ data: [],
623
+ });
624
+ const renderResult = renderTestTable(sortableConfig);
625
+ const table = new TablePage(renderResult);
626
+ // Try to sort with no data (column 1 is First Name)
627
+ const firstNameHeader = table.getHeaderCellByIndex(1);
628
+ expect(firstNameHeader).toBeTruthy();
629
+ fireEvent.click(firstNameHeader);
630
+ // Verify sorting state is set even with no data
631
+ expect(table.header.isColumnSorted(1)).toBe(true);
632
+ expect(table.header.getColumnSortDirection(1)).toBe('asc');
633
+ expect(table.getRowCount()).toBe(0);
634
+ });
635
+ it('should handle rapid sorting changes', () => {
636
+ const sortableConfig = createTestTableConfig({
637
+ columns: [
638
+ {
639
+ field: 'firstName',
640
+ title: 'First Name',
641
+ type: 'string',
642
+ sortable: true,
643
+ },
644
+ {
645
+ field: 'status',
646
+ title: 'Status',
647
+ type: 'string',
648
+ sortable: true,
649
+ },
650
+ {
651
+ field: 'payment',
652
+ title: 'Payment',
653
+ type: 'number',
654
+ sortable: true,
655
+ },
656
+ ],
657
+ });
658
+ const renderResult = renderTestTable(sortableConfig);
659
+ const table = new TablePage(renderResult);
660
+ // Rapidly click different headers
661
+ const firstNameHeader = table.getHeaderCellByIndex(1);
662
+ const statusHeader = table.getHeaderCellByIndex(2);
663
+ const paymentHeader = table.getHeaderCellByIndex(3);
664
+ expect(firstNameHeader).toBeTruthy();
665
+ expect(statusHeader).toBeTruthy();
666
+ expect(paymentHeader).toBeTruthy();
667
+ fireEvent.click(firstNameHeader);
668
+ fireEvent.click(statusHeader);
669
+ fireEvent.click(paymentHeader);
670
+ // Verify only the last clicked column is sorted
671
+ expect(table.header.isColumnSorted(1)).toBe(false);
672
+ expect(table.header.isColumnSorted(2)).toBe(false);
673
+ expect(table.header.isColumnSorted(3)).toBe(true);
674
+ expect(table.header.getColumnSortDirection(3)).toBe('asc');
675
+ });
676
+ it('should handle sorting with duplicate values', () => {
677
+ const duplicateData = [
678
+ createMockPerson({ firstName: 'Alice', payment: 100 }),
679
+ createMockPerson({ firstName: 'Bob', payment: 100 }),
680
+ createMockPerson({ firstName: 'Charlie', payment: 200 }),
681
+ createMockPerson({ firstName: 'Alice', payment: 150 }),
682
+ ];
683
+ const sortableConfig = createTestTableConfig({
684
+ columns: [
685
+ {
686
+ field: 'firstName',
687
+ title: 'First Name',
688
+ type: 'string',
689
+ sortable: true,
690
+ },
691
+ {
692
+ field: 'payment',
693
+ title: 'Payment',
694
+ type: 'number',
695
+ sortable: true,
696
+ },
697
+ ],
698
+ data: duplicateData,
699
+ });
700
+ const renderResult = renderTestTable(sortableConfig);
701
+ const table = new TablePage(renderResult);
702
+ // Sort by firstName with duplicates (column 1 is First Name)
703
+ const firstNameHeader = table.getHeaderCellByIndex(1);
704
+ expect(firstNameHeader).toBeTruthy();
705
+ fireEvent.click(firstNameHeader);
706
+ // Verify sorting handles duplicates correctly
707
+ expect(table.header.isColumnSorted(1)).toBe(true);
708
+ expect(table.header.getColumnSortDirection(1)).toBe('asc');
709
+ const firstNameValues = table.cell.getColumnCells(1);
710
+ expect(firstNameValues[0]).toBe('Alice');
711
+ expect(firstNameValues[1]).toBe('Alice');
712
+ expect(firstNameValues[2]).toBe('Bob');
713
+ expect(firstNameValues[3]).toBe('Charlie');
714
+ });
715
+ });
716
+ describe('Visual Indicators', () => {
717
+ it('should show sort indicators on sortable columns', () => {
718
+ const sortableConfig = createTestTableConfig({
719
+ columns: [
720
+ {
721
+ field: 'firstName',
722
+ title: 'First Name',
723
+ type: 'string',
724
+ sortable: true,
725
+ },
726
+ {
727
+ field: 'status',
728
+ title: 'Status',
729
+ type: 'string',
730
+ sortable: false,
731
+ },
732
+ {
733
+ field: 'payment',
734
+ title: 'Payment',
735
+ type: 'number',
736
+ sortable: true,
737
+ },
738
+ ],
739
+ });
740
+ const renderResult = renderTestTable(sortableConfig);
741
+ const table = new TablePage(renderResult);
742
+ // Verify sortable columns have sort indicators
743
+ expect(table.header.isColumnSortable(1)).toBe(true); // firstName
744
+ expect(table.header.isColumnSortable(2)).toBe(false); // status
745
+ expect(table.header.isColumnSortable(3)).toBe(true); // payment
746
+ // Sort a column and verify visual state
747
+ const firstNameHeader = table.getHeaderCellByIndex(1);
748
+ expect(firstNameHeader).toBeTruthy();
749
+ fireEvent.click(firstNameHeader);
750
+ expect(table.header.isColumnSorted(1)).toBe(true);
751
+ expect(table.header.getColumnSortDirection(1)).toBe('asc');
752
+ });
753
+ it('should update sort indicators when sorting changes', () => {
754
+ const sortableConfig = createTestTableConfig({
755
+ columns: [
756
+ {
757
+ field: 'firstName',
758
+ title: 'First Name',
759
+ type: 'string',
760
+ sortable: true,
761
+ },
762
+ {
763
+ field: 'status',
764
+ title: 'Status',
765
+ type: 'string',
766
+ sortable: true,
767
+ },
768
+ ],
769
+ });
770
+ const renderResult = renderTestTable(sortableConfig);
771
+ const table = new TablePage(renderResult);
772
+ // Initial state - no sorting
773
+ expect(table.header.isColumnSorted(1)).toBe(false);
774
+ expect(table.header.isColumnSorted(2)).toBe(false);
775
+ // Sort firstName ascending (column 1 is First Name)
776
+ const firstNameHeader = table.getHeaderCellByIndex(1);
777
+ expect(firstNameHeader).toBeTruthy();
778
+ fireEvent.click(firstNameHeader);
779
+ expect(table.header.isColumnSorted(1)).toBe(true);
780
+ expect(table.header.getColumnSortDirection(1)).toBe('asc');
781
+ expect(table.header.isColumnSorted(2)).toBe(false);
782
+ // Sort firstName descending
783
+ fireEvent.click(firstNameHeader);
784
+ expect(table.header.isColumnSorted(1)).toBe(true);
785
+ expect(table.header.getColumnSortDirection(1)).toBe('desc');
786
+ // Clear sorting
787
+ fireEvent.click(firstNameHeader);
788
+ expect(table.header.isColumnSorted(1)).toBe(false);
789
+ expect(table.header.getColumnSortDirection(1)).toBe(null);
790
+ });
791
+ });
792
+ });
793
+ //# sourceMappingURL=sorting.test.js.map