@svgrid/grid 1.1.1 → 1.2.1

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 (188) hide show
  1. package/dist/FlexRender.svelte +96 -96
  2. package/dist/SvGrid.controller.svelte.js +17 -6
  3. package/dist/SvGrid.css +2012 -2012
  4. package/dist/SvGrid.svelte +2571 -2346
  5. package/dist/SvGridDropdown.svelte +7 -3
  6. package/dist/build-api.js +2 -2
  7. package/dist/cdn/svgrid.js +13504 -0
  8. package/dist/cdn/svgrid.svelte-external.js +11188 -0
  9. package/dist/cell-values.d.ts +1 -1
  10. package/dist/cell-values.js +7 -7
  11. package/dist/column-types.js +1 -1
  12. package/dist/core.d.ts +1 -1
  13. package/dist/core.js +2 -2
  14. package/dist/summaries.js +4 -4
  15. package/package.json +12 -2
  16. package/src/FlexRender.svelte +96 -96
  17. package/src/SvGrid.controller.svelte.ts +2363 -2352
  18. package/src/SvGrid.css +2012 -2012
  19. package/src/SvGrid.svelte +2571 -2346
  20. package/src/SvGrid.types.ts +537 -537
  21. package/src/SvGridDropdown.svelte +7 -3
  22. package/src/a11y.contract.test.ts +49 -49
  23. package/src/a11y.test.ts +59 -59
  24. package/src/a11y.ts +59 -59
  25. package/src/build-api.ts +683 -683
  26. package/src/cell-formatting.ts +169 -169
  27. package/src/cell-values.ts +4 -4
  28. package/src/column-types.ts +1 -1
  29. package/src/core.performance.test.ts +30 -30
  30. package/src/core.ts +1077 -1077
  31. package/src/createGrid.svelte.ts +42 -42
  32. package/src/createGrid.test.ts +10 -10
  33. package/src/createGridState.svelte.ts +17 -17
  34. package/src/editing.ts +669 -669
  35. package/src/flex-render.ts +3 -3
  36. package/src/index.ts +208 -208
  37. package/src/keyboard.test.ts +59 -59
  38. package/src/keyboard.ts +97 -97
  39. package/src/merge-objects.ts +48 -48
  40. package/src/render-component.ts +28 -28
  41. package/src/spreadsheet.test.ts +489 -489
  42. package/src/spreadsheet.ts +304 -304
  43. package/src/static-functions.ts +11 -11
  44. package/src/subscribe.ts +38 -38
  45. package/src/summaries.ts +4 -4
  46. package/src/svgrid-wrapper.types.ts +412 -412
  47. package/src/svgrid.features.test.ts +157 -157
  48. package/src/svgrid.wrapper.test.ts +40 -40
  49. package/src/virtualization/column-virtualizer.test.ts +27 -27
  50. package/src/virtualization/column-virtualizer.ts +30 -30
  51. package/src/virtualization/svelte-virtualizer.svelte.ts +26 -26
  52. package/src/virtualization/types.ts +30 -30
  53. package/src/virtualization/virtualizer.test.ts +47 -47
  54. package/src/virtualization/virtualizer.ts +296 -296
  55. package/dist/SvGrid.helpers.test.d.ts +0 -1
  56. package/dist/SvGrid.helpers.test.js +0 -298
  57. package/dist/SvGridChart.test.d.ts +0 -1
  58. package/dist/SvGridChart.test.js +0 -62
  59. package/dist/a11y.contract.test.d.ts +0 -1
  60. package/dist/a11y.contract.test.js +0 -39
  61. package/dist/a11y.test.d.ts +0 -1
  62. package/dist/a11y.test.js +0 -44
  63. package/dist/aligned-grids.test.d.ts +0 -1
  64. package/dist/aligned-grids.test.js +0 -75
  65. package/dist/build-api.coverage.test.d.ts +0 -20
  66. package/dist/build-api.coverage.test.js +0 -505
  67. package/dist/cell-formatting.test.d.ts +0 -1
  68. package/dist/cell-formatting.test.js +0 -234
  69. package/dist/cell-render.test.d.ts +0 -1
  70. package/dist/cell-render.test.js +0 -338
  71. package/dist/chart-export.test.d.ts +0 -1
  72. package/dist/chart-export.test.js +0 -302
  73. package/dist/chart.coverage.test.d.ts +0 -1
  74. package/dist/chart.coverage.test.js +0 -748
  75. package/dist/chart.test.d.ts +0 -1
  76. package/dist/chart.test.js +0 -289
  77. package/dist/clipboard.test.d.ts +0 -1
  78. package/dist/clipboard.test.js +0 -700
  79. package/dist/collaboration.coverage.test.d.ts +0 -1
  80. package/dist/collaboration.coverage.test.js +0 -200
  81. package/dist/collaboration.test.d.ts +0 -1
  82. package/dist/collaboration.test.js +0 -65
  83. package/dist/column-groups.test.d.ts +0 -1
  84. package/dist/column-groups.test.js +0 -56
  85. package/dist/column-types.test.d.ts +0 -1
  86. package/dist/column-types.test.js +0 -62
  87. package/dist/columns.test.d.ts +0 -1
  88. package/dist/columns.test.js +0 -625
  89. package/dist/conditional-formatting.test.d.ts +0 -1
  90. package/dist/conditional-formatting.test.js +0 -87
  91. package/dist/core.coverage.test.d.ts +0 -1
  92. package/dist/core.coverage.test.js +0 -186
  93. package/dist/core.performance.test.d.ts +0 -1
  94. package/dist/core.performance.test.js +0 -29
  95. package/dist/createGrid.test.d.ts +0 -1
  96. package/dist/createGrid.test.js +0 -9
  97. package/dist/editing.test.d.ts +0 -1
  98. package/dist/editing.test.js +0 -732
  99. package/dist/editors/cell-editors.coverage.test.d.ts +0 -1
  100. package/dist/editors/cell-editors.coverage.test.js +0 -139
  101. package/dist/editors/cell-editors.test.d.ts +0 -1
  102. package/dist/editors/cell-editors.test.js +0 -75
  103. package/dist/facet-buckets.test.d.ts +0 -1
  104. package/dist/facet-buckets.test.js +0 -296
  105. package/dist/fill-patterns.test.d.ts +0 -1
  106. package/dist/fill-patterns.test.js +0 -81
  107. package/dist/filter-operators.test.d.ts +0 -1
  108. package/dist/filter-operators.test.js +0 -135
  109. package/dist/filtering/excel-filters.test.d.ts +0 -1
  110. package/dist/filtering/excel-filters.test.js +0 -116
  111. package/dist/filtering/locale-filter.test.d.ts +0 -13
  112. package/dist/filtering/locale-filter.test.js +0 -189
  113. package/dist/flex-render.test.d.ts +0 -1
  114. package/dist/flex-render.test.js +0 -142
  115. package/dist/group-aggregate.test.d.ts +0 -1
  116. package/dist/group-aggregate.test.js +0 -32
  117. package/dist/hyperformula-adapter.test.d.ts +0 -1
  118. package/dist/hyperformula-adapter.test.js +0 -205
  119. package/dist/keyboard-handlers.coverage.test.d.ts +0 -1
  120. package/dist/keyboard-handlers.coverage.test.js +0 -495
  121. package/dist/keyboard.test.d.ts +0 -1
  122. package/dist/keyboard.test.js +0 -27
  123. package/dist/menus.test.d.ts +0 -1
  124. package/dist/menus.test.js +0 -560
  125. package/dist/named-views.coverage.test.d.ts +0 -1
  126. package/dist/named-views.coverage.test.js +0 -180
  127. package/dist/named-views.test.d.ts +0 -1
  128. package/dist/named-views.test.js +0 -57
  129. package/dist/new-features.test.d.ts +0 -1
  130. package/dist/new-features.test.js +0 -183
  131. package/dist/render-component.test.d.ts +0 -1
  132. package/dist/render-component.test.js +0 -41
  133. package/dist/row-drag.test.d.ts +0 -1
  134. package/dist/row-drag.test.js +0 -142
  135. package/dist/row-resize.test.d.ts +0 -1
  136. package/dist/row-resize.test.js +0 -329
  137. package/dist/scroll-sync.test.d.ts +0 -1
  138. package/dist/scroll-sync.test.js +0 -290
  139. package/dist/selection.multi-range.test.d.ts +0 -1
  140. package/dist/selection.multi-range.test.js +0 -55
  141. package/dist/selection.test.d.ts +0 -1
  142. package/dist/selection.test.js +0 -647
  143. package/dist/server-data-source.coverage.test.d.ts +0 -1
  144. package/dist/server-data-source.coverage.test.js +0 -154
  145. package/dist/server-data-source.test.d.ts +0 -1
  146. package/dist/server-data-source.test.js +0 -81
  147. package/dist/sparkline.test.d.ts +0 -1
  148. package/dist/sparkline.test.js +0 -52
  149. package/dist/spreadsheet.test.d.ts +0 -1
  150. package/dist/spreadsheet.test.js +0 -446
  151. package/dist/subscribe.test.d.ts +0 -1
  152. package/dist/subscribe.test.js +0 -93
  153. package/dist/svgrid.api-extensions.test.d.ts +0 -14
  154. package/dist/svgrid.api-extensions.test.js +0 -334
  155. package/dist/svgrid.api.test.d.ts +0 -15
  156. package/dist/svgrid.api.test.js +0 -169
  157. package/dist/svgrid.behavior.test.d.ts +0 -15
  158. package/dist/svgrid.behavior.test.js +0 -625
  159. package/dist/svgrid.column-reorder.test.d.ts +0 -15
  160. package/dist/svgrid.column-reorder.test.js +0 -224
  161. package/dist/svgrid.comments-autocomplete.test.d.ts +0 -1
  162. package/dist/svgrid.comments-autocomplete.test.js +0 -96
  163. package/dist/svgrid.context-menu.test.d.ts +0 -1
  164. package/dist/svgrid.context-menu.test.js +0 -102
  165. package/dist/svgrid.features.test.d.ts +0 -1
  166. package/dist/svgrid.features.test.js +0 -129
  167. package/dist/svgrid.interaction.test.d.ts +0 -9
  168. package/dist/svgrid.interaction.test.js +0 -349
  169. package/dist/svgrid.locale-filtering.test.d.ts +0 -15
  170. package/dist/svgrid.locale-filtering.test.js +0 -261
  171. package/dist/svgrid.new-features.wrapper.test.d.ts +0 -1
  172. package/dist/svgrid.new-features.wrapper.test.js +0 -194
  173. package/dist/svgrid.row-pinning.test.d.ts +0 -14
  174. package/dist/svgrid.row-pinning.test.js +0 -250
  175. package/dist/svgrid.set-filter.test.d.ts +0 -17
  176. package/dist/svgrid.set-filter.test.js +0 -268
  177. package/dist/svgrid.wrapper.test.d.ts +0 -1
  178. package/dist/svgrid.wrapper.test.js +0 -59
  179. package/dist/test-setup.d.ts +0 -1
  180. package/dist/test-setup.js +0 -35
  181. package/dist/transaction.test.d.ts +0 -1
  182. package/dist/transaction.test.js +0 -89
  183. package/dist/virtualization/column-virtualizer.test.d.ts +0 -1
  184. package/dist/virtualization/column-virtualizer.test.js +0 -25
  185. package/dist/virtualization/scroll-scaling.test.d.ts +0 -1
  186. package/dist/virtualization/scroll-scaling.test.js +0 -127
  187. package/dist/virtualization/virtualizer.test.d.ts +0 -1
  188. package/dist/virtualization/virtualizer.test.js +0 -41
@@ -1,334 +0,0 @@
1
- /**
2
- * Behavioral tests for the SvGridApi extensions inspired by the jqxGrid API:
3
- * - Row selection read/write (getSelectedRows / getSelectedRowIds /
4
- * selectRows / selectAllRows / toggleRowSelected)
5
- * - Pagination control (getPageInfo / setPage / next/prev/first/last /
6
- * setPageSize)
7
- * - Navigation (scrollToRow / getActiveCell / setActiveCell)
8
- * - View state (getState / setState / refresh)
9
- * - Click / double-click / scroll-bottom events
10
- *
11
- * They mount the real <SvGrid /> in jsdom and exercise the api object handed
12
- * back from onApiReady.
13
- */
14
- import { describe, expect, it } from 'vitest';
15
- import { mount, unmount } from 'svelte';
16
- import SvGrid from './SvGrid.svelte';
17
- import { columnFilteringFeature, getGridCellDomId, rowPaginationFeature, rowSelectionFeature, rowSortingFeature, tableFeatures, } from './index';
18
- const sampleRows = [
19
- { id: 1, name: 'Ada Lovelace', team: 'Research', salary: 142000 },
20
- { id: 2, name: 'Grace Hopper', team: 'Compilers', salary: 158000 },
21
- { id: 3, name: 'Alan Turing', team: 'Research', salary: 138000 },
22
- { id: 4, name: 'Margaret Hamilton', team: 'Apollo', salary: 165000 },
23
- { id: 5, name: 'Linus Torvalds', team: 'Kernel', salary: 175000 },
24
- ];
25
- const sampleColumns = [
26
- { field: 'name', header: 'Name', width: 200 },
27
- { field: 'team', header: 'Team', width: 160 },
28
- { field: 'salary', header: 'Salary', width: 140 },
29
- ];
30
- // One microtask is enough for the grid's derived state (gridStateVersion) to
31
- // re-run after an imperative mutation - mirrors the existing api test.
32
- const flush = () => Promise.resolve();
33
- function mountGrid(extraProps = {}, features = tableFeatures({
34
- columnFilteringFeature,
35
- rowSortingFeature,
36
- rowSelectionFeature,
37
- })) {
38
- return new Promise((resolveApi, rejectApi) => {
39
- const target = document.createElement('div');
40
- document.body.appendChild(target);
41
- let captured = null;
42
- const app = mount(SvGrid, {
43
- target,
44
- props: {
45
- data: sampleRows,
46
- columns: sampleColumns,
47
- features,
48
- rowHeight: 36,
49
- containerHeight: 480,
50
- virtualization: false,
51
- onApiReady(api) {
52
- captured = api;
53
- resolveApi({
54
- api,
55
- target,
56
- destroy: () => {
57
- unmount(app);
58
- target.remove();
59
- },
60
- });
61
- },
62
- ...extraProps,
63
- },
64
- });
65
- queueMicrotask(() => {
66
- if (!captured)
67
- rejectApi(new Error('onApiReady never fired'));
68
- });
69
- });
70
- }
71
- describe('SvGridApi - row selection', () => {
72
- it('selectAllRows selects every row; getSelectedRows / Ids reflect it', async () => {
73
- const { api, destroy } = await mountGrid();
74
- try {
75
- api.selectAllRows();
76
- await flush();
77
- expect(api.getSelectedRows().length).toBe(5);
78
- expect(api.getSelectedRowIds().length).toBe(5);
79
- }
80
- finally {
81
- destroy();
82
- }
83
- });
84
- it('selectRows replaces the selection by default and adds with additive', async () => {
85
- const { api, destroy } = await mountGrid();
86
- try {
87
- api.selectAllRows();
88
- await flush();
89
- const ids = api.getSelectedRowIds();
90
- expect(ids.length).toBe(5);
91
- api.selectRows([ids[0]]);
92
- await flush();
93
- expect(api.getSelectedRowIds()).toEqual([ids[0]]);
94
- api.selectRows([ids[1]], true);
95
- await flush();
96
- expect(new Set(api.getSelectedRowIds())).toEqual(new Set([ids[0], ids[1]]));
97
- }
98
- finally {
99
- destroy();
100
- }
101
- });
102
- it('toggleRowSelected flips one row; clearRowSelection wipes all', async () => {
103
- const { api, destroy } = await mountGrid();
104
- try {
105
- api.selectAllRows();
106
- await flush();
107
- const id = api.getSelectedRowIds()[0];
108
- api.toggleRowSelected(id);
109
- await flush();
110
- expect(api.getSelectedRowIds()).not.toContain(id);
111
- api.clearRowSelection();
112
- await flush();
113
- expect(api.getSelectedRowIds().length).toBe(0);
114
- }
115
- finally {
116
- destroy();
117
- }
118
- });
119
- });
120
- describe('SvGridApi - pagination', () => {
121
- const paged = () => mountGrid({ showPagination: true, pageSize: 2 }, tableFeatures({ rowPaginationFeature }));
122
- it('getPageInfo derives pageCount from the filtered total', async () => {
123
- const { api, destroy } = await paged();
124
- try {
125
- const info = api.getPageInfo();
126
- expect(info.total).toBe(5);
127
- expect(info.pageSize).toBe(2);
128
- expect(info.pageCount).toBe(3); // ceil(5 / 2)
129
- expect(info.pageIndex).toBe(0);
130
- }
131
- finally {
132
- destroy();
133
- }
134
- });
135
- it('setPage clamps to [0, pageCount - 1]', async () => {
136
- const { api, destroy } = await paged();
137
- try {
138
- api.setPage(99);
139
- await flush();
140
- expect(api.getPageInfo().pageIndex).toBe(2);
141
- api.setPage(-5);
142
- await flush();
143
- expect(api.getPageInfo().pageIndex).toBe(0);
144
- }
145
- finally {
146
- destroy();
147
- }
148
- });
149
- it('next/prev/first/last move through the pages', async () => {
150
- const { api, destroy } = await paged();
151
- try {
152
- api.nextPage();
153
- await flush();
154
- expect(api.getPageInfo().pageIndex).toBe(1);
155
- api.lastPage();
156
- await flush();
157
- expect(api.getPageInfo().pageIndex).toBe(2);
158
- api.prevPage();
159
- await flush();
160
- expect(api.getPageInfo().pageIndex).toBe(1);
161
- api.firstPage();
162
- await flush();
163
- expect(api.getPageInfo().pageIndex).toBe(0);
164
- }
165
- finally {
166
- destroy();
167
- }
168
- });
169
- it('setPageSize updates the page size and recomputes pageCount', async () => {
170
- const { api, destroy } = await paged();
171
- try {
172
- api.setPageSize(5);
173
- await flush();
174
- const info = api.getPageInfo();
175
- expect(info.pageSize).toBe(5);
176
- expect(info.pageCount).toBe(1);
177
- }
178
- finally {
179
- destroy();
180
- }
181
- });
182
- });
183
- describe('SvGridApi - navigation', () => {
184
- it('setActiveCell + getActiveCell round-trip with the column id', async () => {
185
- const { api, destroy } = await mountGrid();
186
- try {
187
- api.setActiveCell(2, 1);
188
- await flush();
189
- expect(api.getActiveCell()).toEqual({
190
- rowIndex: 2,
191
- colIndex: 1,
192
- columnId: 'team',
193
- });
194
- }
195
- finally {
196
- destroy();
197
- }
198
- });
199
- it('setActiveCell clamps out-of-range coordinates', async () => {
200
- const { api, destroy } = await mountGrid();
201
- try {
202
- api.setActiveCell(999, 999);
203
- await flush();
204
- const cell = api.getActiveCell();
205
- expect(cell?.rowIndex).toBe(4); // last row
206
- expect(cell?.colIndex).toBe(2); // last column
207
- }
208
- finally {
209
- destroy();
210
- }
211
- });
212
- it('scrollToRow does not throw for valid or out-of-range indices', async () => {
213
- const { api, destroy } = await mountGrid();
214
- try {
215
- expect(() => api.scrollToRow(3)).not.toThrow();
216
- expect(() => api.scrollToRow(9999)).not.toThrow();
217
- }
218
- finally {
219
- destroy();
220
- }
221
- });
222
- });
223
- describe('SvGridApi - view state (getState / setState)', () => {
224
- it('getState captures sort + filters; setState restores them', async () => {
225
- const { api, destroy } = await mountGrid();
226
- try {
227
- api.setSort('salary', 'desc');
228
- api.setFilter('team', { operator: 'equals', value: 'Research' });
229
- await flush();
230
- const snapshot = api.getState();
231
- expect(snapshot.sorting).toEqual([{ id: 'salary', desc: true }]);
232
- expect(snapshot.columnFilters.team).toEqual({
233
- operator: 'equals',
234
- value: 'Research',
235
- });
236
- // Wipe, then restore from the snapshot.
237
- api.clearSort();
238
- api.clearAllFilters();
239
- await flush();
240
- expect(api.getState().sorting).toEqual([]);
241
- expect(api.getFilters()).toEqual({});
242
- api.setState(snapshot);
243
- await flush();
244
- expect(api.getState().sorting).toEqual([{ id: 'salary', desc: true }]);
245
- expect(api.getFilters().team).toEqual({
246
- operator: 'equals',
247
- value: 'Research',
248
- });
249
- }
250
- finally {
251
- destroy();
252
- }
253
- });
254
- it('setState restores column width + visibility', async () => {
255
- const { api, destroy } = await mountGrid();
256
- try {
257
- api.setState({ columnWidths: { name: 320 }, hiddenColumns: ['team'] });
258
- await flush();
259
- expect(api.getColumnWidths().name).toBe(320);
260
- expect(api.isColumnVisible('team')).toBe(false);
261
- expect(api.getState().hiddenColumns).toContain('team');
262
- }
263
- finally {
264
- destroy();
265
- }
266
- });
267
- it('partial setState only touches the keys present', async () => {
268
- const { api, destroy } = await mountGrid();
269
- try {
270
- api.setSort('name', 'asc');
271
- await flush();
272
- // Restoring only filters must not clear the existing sort.
273
- api.setState({ globalFilter: '' });
274
- await flush();
275
- expect(api.getState().sorting).toEqual([{ id: 'name', desc: false }]);
276
- }
277
- finally {
278
- destroy();
279
- }
280
- });
281
- });
282
- describe('SvGridApi - click / double-click / scroll events', () => {
283
- function clickCell(_target, rowIndex, colIndex, type) {
284
- const id = getGridCellDomId('svgrid', rowIndex, colIndex);
285
- const el = document.getElementById(id);
286
- if (!el)
287
- throw new Error(`cell ${id} not found`);
288
- el.dispatchEvent(new MouseEvent(type, { bubbles: true }));
289
- }
290
- it('onCellClick + onRowClick fire with the expected payload', async () => {
291
- const cellEvents = [];
292
- const rowEvents = [];
293
- const { target, destroy } = await mountGrid({
294
- onCellClick: (e) => cellEvents.push(e),
295
- onRowClick: (e) => rowEvents.push(e),
296
- });
297
- try {
298
- clickCell(target, 0, 0, 'click');
299
- await flush();
300
- expect(cellEvents.length).toBe(1);
301
- expect(cellEvents[0]).toMatchObject({
302
- rowIndex: 0,
303
- colIndex: 0,
304
- columnId: 'name',
305
- value: 'Ada Lovelace',
306
- });
307
- expect(cellEvents[0].row.id).toBe(1);
308
- expect(rowEvents.length).toBe(1);
309
- expect(rowEvents[0]).toMatchObject({ rowIndex: 0, columnId: 'name' });
310
- }
311
- finally {
312
- destroy();
313
- }
314
- });
315
- it('onCellDoubleClick + onRowDoubleClick fire on dblclick', async () => {
316
- const cellEvents = [];
317
- const rowEvents = [];
318
- const { target, destroy } = await mountGrid({
319
- enableInlineEditing: false,
320
- onCellDoubleClick: (e) => cellEvents.push(e),
321
- onRowDoubleClick: (e) => rowEvents.push(e),
322
- });
323
- try {
324
- clickCell(target, 1, 1, 'dblclick');
325
- await flush();
326
- expect(cellEvents.length).toBe(1);
327
- expect(cellEvents[0]).toMatchObject({ rowIndex: 1, colIndex: 1, columnId: 'team' });
328
- expect(rowEvents.length).toBe(1);
329
- }
330
- finally {
331
- destroy();
332
- }
333
- });
334
- });
@@ -1,15 +0,0 @@
1
- /**
2
- * Behavioral tests for the imperative SvGridApi exposed via `onApiReady`.
3
- *
4
- * These mount the real <SvGrid /> render component in jsdom, capture the api
5
- * object on mount, and exercise:
6
- * - clearAllFilters (new)
7
- * - getFilters (new)
8
- * - getDisplayedRows (new)
9
- * - setFilter (regression)
10
- * - getData (regression)
11
- *
12
- * Bare-bones DOM env is enough; we never assert on rendered HTML, just on
13
- * the object the component hands back.
14
- */
15
- export {};
@@ -1,169 +0,0 @@
1
- /**
2
- * Behavioral tests for the imperative SvGridApi exposed via `onApiReady`.
3
- *
4
- * These mount the real <SvGrid /> render component in jsdom, capture the api
5
- * object on mount, and exercise:
6
- * - clearAllFilters (new)
7
- * - getFilters (new)
8
- * - getDisplayedRows (new)
9
- * - setFilter (regression)
10
- * - getData (regression)
11
- *
12
- * Bare-bones DOM env is enough; we never assert on rendered HTML, just on
13
- * the object the component hands back.
14
- */
15
- import { describe, expect, it } from 'vitest';
16
- import { mount, unmount } from 'svelte';
17
- import SvGrid from './SvGrid.svelte';
18
- import { columnFilteringFeature, createCoreRowModel, createFilteredRowModel, createSortedRowModel, rowSortingFeature, sortFns, tableFeatures, } from './index';
19
- const features = tableFeatures({
20
- columnFilteringFeature,
21
- rowSortingFeature,
22
- });
23
- const sampleRows = [
24
- { id: 1, name: 'Ada Lovelace', team: 'Research', salary: 142000 },
25
- { id: 2, name: 'Grace Hopper', team: 'Compilers', salary: 158000 },
26
- { id: 3, name: 'Alan Turing', team: 'Research', salary: 138000 },
27
- { id: 4, name: 'Margaret Hamilton', team: 'Apollo', salary: 165000 },
28
- { id: 5, name: 'Linus Torvalds', team: 'Kernel', salary: 175000 },
29
- ];
30
- const sampleColumns = [
31
- { field: 'name', header: 'Name', width: 200 },
32
- { field: 'team', header: 'Team', width: 160 },
33
- { field: 'salary', header: 'Salary', width: 140 },
34
- ];
35
- function mountGrid() {
36
- return new Promise((resolveApi, rejectApi) => {
37
- const target = document.createElement('div');
38
- document.body.appendChild(target);
39
- let capturedApi = null;
40
- const app = mount(SvGrid, {
41
- target,
42
- props: {
43
- data: sampleRows,
44
- columns: sampleColumns,
45
- features,
46
- _rowModels: {
47
- coreRowModel: createCoreRowModel(),
48
- filteredRowModel: createFilteredRowModel(),
49
- sortedRowModel: createSortedRowModel(sortFns),
50
- },
51
- rowHeight: 36,
52
- containerHeight: 480,
53
- virtualization: false,
54
- onApiReady(api) {
55
- capturedApi = api;
56
- resolveApi({
57
- api,
58
- destroy: () => {
59
- unmount(app);
60
- target.remove();
61
- },
62
- });
63
- },
64
- },
65
- });
66
- // Safety net: if onApiReady doesn't fire within a turn, fail loudly.
67
- queueMicrotask(() => {
68
- if (!capturedApi)
69
- rejectApi(new Error('onApiReady never fired'));
70
- });
71
- });
72
- }
73
- describe('SvGridApi - getData / getDisplayedRows', () => {
74
- it('getData returns the full row set', async () => {
75
- const { api, destroy } = await mountGrid();
76
- try {
77
- const data = api.getData();
78
- expect(data.length).toBe(sampleRows.length);
79
- expect(data.map((r) => r.id)).toEqual([1, 2, 3, 4, 5]);
80
- }
81
- finally {
82
- destroy();
83
- }
84
- });
85
- it('getDisplayedRows returns the post-pipeline visible rows', async () => {
86
- const { api, destroy } = await mountGrid();
87
- try {
88
- // With no filters / sort, displayed rows match full data (no group rows).
89
- const displayed = api.getDisplayedRows();
90
- expect(displayed.length).toBe(sampleRows.length);
91
- }
92
- finally {
93
- destroy();
94
- }
95
- });
96
- it('getDisplayedRows updates after setFilter narrows the set', async () => {
97
- const { api, destroy } = await mountGrid();
98
- try {
99
- api.setFilter('team', { operator: 'contains', value: 'Research' });
100
- // Wait one microtask so the derived row pipeline re-runs.
101
- await Promise.resolve();
102
- const displayed = api.getDisplayedRows();
103
- // 2 rows have team === 'Research'
104
- expect(displayed.length).toBe(2);
105
- for (const r of displayed) {
106
- expect(r.team).toBe('Research');
107
- }
108
- }
109
- finally {
110
- destroy();
111
- }
112
- });
113
- });
114
- describe('SvGridApi - getFilters / clearAllFilters', () => {
115
- it('getFilters returns an empty object when nothing is filtered', async () => {
116
- const { api, destroy } = await mountGrid();
117
- try {
118
- expect(api.getFilters()).toEqual({});
119
- }
120
- finally {
121
- destroy();
122
- }
123
- });
124
- it('getFilters reflects the last setFilter call', async () => {
125
- const { api, destroy } = await mountGrid();
126
- try {
127
- api.setFilter('team', { operator: 'equals', value: 'Apollo' });
128
- await Promise.resolve();
129
- const filters = api.getFilters();
130
- expect(filters.team).toEqual({ operator: 'equals', value: 'Apollo' });
131
- }
132
- finally {
133
- destroy();
134
- }
135
- });
136
- it('clearAllFilters wipes every column filter at once', async () => {
137
- const { api, destroy } = await mountGrid();
138
- try {
139
- api.setFilter('team', { operator: 'contains', value: 'Research' });
140
- api.setFilter('name', { operator: 'contains', value: 'Ada' });
141
- await Promise.resolve();
142
- expect(Object.keys(api.getFilters()).length).toBe(2);
143
- api.clearAllFilters();
144
- await Promise.resolve();
145
- expect(api.getFilters()).toEqual({});
146
- // The full row set is back.
147
- const displayed = api.getDisplayedRows();
148
- expect(displayed.length).toBe(sampleRows.length);
149
- }
150
- finally {
151
- destroy();
152
- }
153
- });
154
- it('clearAllFilters returns a snapshot that is safe to mutate', async () => {
155
- const { api, destroy } = await mountGrid();
156
- try {
157
- api.setFilter('team', { operator: 'contains', value: 'X' });
158
- await Promise.resolve();
159
- const snapshot = api.getFilters();
160
- // Mutate the snapshot - internal state must not be affected.
161
- snapshot.team.value = 'mutated externally';
162
- const fresh = api.getFilters();
163
- expect(fresh.team.value).toBe('X');
164
- }
165
- finally {
166
- destroy();
167
- }
168
- });
169
- });
@@ -1,15 +0,0 @@
1
- /**
2
- * Broad behavioral test suite for the <SvGrid /> render component.
3
- *
4
- * The intent is wide coverage on a single file - SvGrid.svelte is ~3000
5
- * lines and most of its branches are reachable only when the component is
6
- * mounted with a particular prop combination. Each test below exercises a
7
- * different feature set so the whole file's effect graph is traversed.
8
- *
9
- * Pattern (re-used across files):
10
- * 1. mount SvGrid in jsdom with the props that trigger the feature
11
- * 2. wait one microtask for $effects to flush
12
- * 3. assert on the api object delivered via onApiReady, or on visible DOM
13
- * 4. unmount
14
- */
15
- export {};