@arbor-education/design-system.components 0.1.0 → 0.1.2
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.
- package/CHANGELOG.md +12 -0
- package/dist/components/button/Button.d.ts +1 -0
- package/dist/components/button/Button.d.ts.map +1 -1
- package/dist/components/button/Button.js +2 -1
- package/dist/components/button/Button.js.map +1 -1
- package/dist/components/formField/inputs/number/NumberInput.d.ts +2 -0
- package/dist/components/formField/inputs/number/NumberInput.d.ts.map +1 -1
- package/dist/components/formField/inputs/number/NumberInput.js +9 -4
- package/dist/components/formField/inputs/number/NumberInput.js.map +1 -1
- package/dist/components/table/BulkActionsDropdown.js +2 -2
- package/dist/components/table/BulkActionsDropdown.js.map +1 -1
- package/dist/components/table/GridApiContext.d.ts +1 -2
- package/dist/components/table/GridApiContext.d.ts.map +1 -1
- package/dist/components/table/GridApiContext.js +1 -1
- package/dist/components/table/GridApiContext.js.map +1 -1
- package/dist/components/table/Table.d.ts +9 -1
- package/dist/components/table/Table.d.ts.map +1 -1
- package/dist/components/table/Table.js +13 -5
- package/dist/components/table/Table.js.map +1 -1
- package/dist/components/table/Table.stories.d.ts +5 -1
- package/dist/components/table/Table.stories.d.ts.map +1 -1
- package/dist/components/table/Table.stories.js +36 -1
- package/dist/components/table/Table.stories.js.map +1 -1
- package/dist/components/table/Table.test.js +2 -0
- package/dist/components/table/Table.test.js.map +1 -1
- package/dist/components/table/pagination/PageSizeSelector.d.ts +7 -0
- package/dist/components/table/pagination/PageSizeSelector.d.ts.map +1 -0
- package/dist/components/table/pagination/PageSizeSelector.js +46 -0
- package/dist/components/table/pagination/PageSizeSelector.js.map +1 -0
- package/dist/components/table/pagination/Pagination.test.d.ts +2 -0
- package/dist/components/table/pagination/Pagination.test.d.ts.map +1 -0
- package/dist/components/table/pagination/Pagination.test.js +616 -0
- package/dist/components/table/pagination/Pagination.test.js.map +1 -0
- package/dist/components/table/pagination/PaginationControls.d.ts +6 -0
- package/dist/components/table/pagination/PaginationControls.d.ts.map +1 -0
- package/dist/components/table/pagination/PaginationControls.js +47 -0
- package/dist/components/table/pagination/PaginationControls.js.map +1 -0
- package/dist/components/table/pagination/PaginationPanel.d.ts +9 -0
- package/dist/components/table/pagination/PaginationPanel.d.ts.map +1 -0
- package/dist/components/table/pagination/PaginationPanel.js +11 -0
- package/dist/components/table/pagination/PaginationPanel.js.map +1 -0
- package/dist/components/table/pagination/RowCountInfo.d.ts +5 -0
- package/dist/components/table/pagination/RowCountInfo.d.ts.map +1 -0
- package/dist/components/table/pagination/RowCountInfo.js +53 -0
- package/dist/components/table/pagination/RowCountInfo.js.map +1 -0
- package/dist/components/tooltip/Tooltip.d.ts +7 -0
- package/dist/components/tooltip/Tooltip.d.ts.map +1 -0
- package/dist/components/tooltip/Tooltip.js +11 -0
- package/dist/components/tooltip/Tooltip.js.map +1 -0
- package/dist/components/tooltip/Tooltip.stories.d.ts +10 -0
- package/dist/components/tooltip/Tooltip.stories.d.ts.map +1 -0
- package/dist/components/tooltip/Tooltip.stories.js +24 -0
- package/dist/components/tooltip/Tooltip.stories.js.map +1 -0
- package/dist/components/tooltip/Tooltip.test.d.ts +2 -0
- package/dist/components/tooltip/Tooltip.test.d.ts.map +1 -0
- package/dist/components/tooltip/Tooltip.test.js +23 -0
- package/dist/components/tooltip/Tooltip.test.js.map +1 -0
- package/dist/components/tooltip/TooltipContent.d.ts +8 -0
- package/dist/components/tooltip/TooltipContent.d.ts.map +1 -0
- package/dist/components/tooltip/TooltipContent.js +11 -0
- package/dist/components/tooltip/TooltipContent.js.map +1 -0
- package/dist/components/tooltip/TooltipTrigger.d.ts +3 -0
- package/dist/components/tooltip/TooltipTrigger.d.ts.map +1 -0
- package/dist/components/tooltip/TooltipTrigger.js +8 -0
- package/dist/components/tooltip/TooltipTrigger.js.map +1 -0
- package/dist/components/tooltip/TooltipWrapper.d.ts +11 -0
- package/dist/components/tooltip/TooltipWrapper.d.ts.map +1 -0
- package/dist/components/tooltip/TooltipWrapper.js +8 -0
- package/dist/components/tooltip/TooltipWrapper.js.map +1 -0
- package/dist/components/tooltip/TooltipWrapper.stories.d.ts +11 -0
- package/dist/components/tooltip/TooltipWrapper.stories.d.ts.map +1 -0
- package/dist/components/tooltip/TooltipWrapper.stories.js +23 -0
- package/dist/components/tooltip/TooltipWrapper.stories.js.map +1 -0
- package/dist/components/tooltip/TooltipWrapper.test.d.ts +2 -0
- package/dist/components/tooltip/TooltipWrapper.test.d.ts.map +1 -0
- package/dist/components/tooltip/TooltipWrapper.test.js +42 -0
- package/dist/components/tooltip/TooltipWrapper.test.js.map +1 -0
- package/dist/index.css +41 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/hooks/useGridApi.d.ts +5 -0
- package/dist/utils/hooks/useGridApi.d.ts.map +1 -0
- package/dist/utils/hooks/useGridApi.js +13 -0
- package/dist/utils/hooks/useGridApi.js.map +1 -0
- package/dist/utils/hooks/useIsMounted.d.ts +2 -0
- package/dist/utils/hooks/useIsMounted.d.ts.map +1 -0
- package/dist/utils/hooks/useIsMounted.js +12 -0
- package/dist/utils/hooks/useIsMounted.js.map +1 -0
- package/package.json +1 -1
- package/release/design-system.components.tgz +0 -0
- package/src/components/button/Button.tsx +3 -0
- package/src/components/button/button.scss +4 -0
- package/src/components/formField/inputs/number/NumberInput.tsx +39 -24
- package/src/components/table/BulkActionsDropdown.tsx +2 -2
- package/src/components/table/GridApiContext.ts +2 -2
- package/src/components/table/Table.stories.tsx +64 -2
- package/src/components/table/Table.test.tsx +2 -0
- package/src/components/table/Table.tsx +14 -4
- package/src/components/table/pagination/PageSizeSelector.tsx +73 -0
- package/src/components/table/pagination/Pagination.test.tsx +846 -0
- package/src/components/table/pagination/PaginationControls.tsx +116 -0
- package/src/components/table/pagination/PaginationPanel.tsx +30 -0
- package/src/components/table/pagination/RowCountInfo.tsx +67 -0
- package/src/components/table/pagination/pagination.scss +26 -0
- package/src/components/tooltip/Tooltip.stories.tsx +35 -0
- package/src/components/tooltip/Tooltip.test.tsx +44 -0
- package/src/components/tooltip/Tooltip.tsx +18 -0
- package/src/components/tooltip/TooltipContent.tsx +40 -0
- package/src/components/tooltip/TooltipTrigger.tsx +11 -0
- package/src/components/tooltip/TooltipWrapper.stories.tsx +24 -0
- package/src/components/tooltip/TooltipWrapper.test.tsx +100 -0
- package/src/components/tooltip/TooltipWrapper.tsx +32 -0
- package/src/components/tooltip/tooltip.scss +15 -0
- package/src/index.scss +2 -0
- package/src/index.ts +2 -0
- package/src/utils/hooks/useGridApi.ts +15 -0
- package/src/utils/hooks/useIsMounted.ts +12 -0
|
@@ -0,0 +1,846 @@
|
|
|
1
|
+
import { describe, expect, test, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import '@testing-library/jest-dom/vitest';
|
|
5
|
+
import userEvent from '@testing-library/user-event';
|
|
6
|
+
import type { AgEvent, GridApi } from 'ag-grid-enterprise';
|
|
7
|
+
import { PaginationControls } from './PaginationControls';
|
|
8
|
+
import { RowCountInfo } from './RowCountInfo';
|
|
9
|
+
import { PageSizeSelector } from './PageSizeSelector';
|
|
10
|
+
import { PaginationPanel } from './PaginationPanel';
|
|
11
|
+
import { GridApiContext } from '../GridApiContext';
|
|
12
|
+
|
|
13
|
+
describe('Table Pagination', () => {
|
|
14
|
+
const createMockGridApi = (overrides?: Partial<GridApi>): Partial<GridApi> => {
|
|
15
|
+
const mockListeners: Record<string, Array<() => void>> = {
|
|
16
|
+
paginationChanged: [],
|
|
17
|
+
filterChanged: [],
|
|
18
|
+
rowDataUpdated: [],
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const result = {
|
|
22
|
+
getDisplayedRowCount: vi.fn(() => 10),
|
|
23
|
+
paginationGetPageSize: vi.fn(() => 10),
|
|
24
|
+
paginationGetCurrentPage: vi.fn(() => 0),
|
|
25
|
+
paginationGetTotalPages: vi.fn(() => 1),
|
|
26
|
+
paginationGetRowCount: vi.fn(() => 10),
|
|
27
|
+
paginationGoToPage: vi.fn(),
|
|
28
|
+
addEventListener: vi.fn((event: string, callback: () => void) => {
|
|
29
|
+
if (!mockListeners[event]) {
|
|
30
|
+
mockListeners[event] = [];
|
|
31
|
+
}
|
|
32
|
+
mockListeners[event].push(callback);
|
|
33
|
+
}),
|
|
34
|
+
removeEventListener: vi.fn(),
|
|
35
|
+
dispatchEvent: (evtName: string) => {
|
|
36
|
+
mockListeners[evtName]?.forEach((callback) => {
|
|
37
|
+
callback();
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
...overrides,
|
|
41
|
+
} as Partial<GridApi> & {
|
|
42
|
+
mockListeners: typeof mockListeners;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return result;
|
|
46
|
+
};
|
|
47
|
+
describe('PaginationControls', () => {
|
|
48
|
+
const renderWithContext = (
|
|
49
|
+
component: React.ReactElement,
|
|
50
|
+
gridApi: Partial<GridApi> | null = null,
|
|
51
|
+
) => {
|
|
52
|
+
return render(
|
|
53
|
+
<GridApiContext.Provider value={gridApi as GridApi | null}>
|
|
54
|
+
{component}
|
|
55
|
+
</GridApiContext.Provider>,
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
test('renders pagination controls container', () => {
|
|
60
|
+
const { container } = renderWithContext(<PaginationControls totalPages={5} />);
|
|
61
|
+
expect(container.querySelector('.ds-table__pagination-controls')).toBeInTheDocument();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('renders all navigation buttons', () => {
|
|
65
|
+
renderWithContext(<PaginationControls totalPages={5} />);
|
|
66
|
+
expect(screen.getByText('Go to first page')).toBeInTheDocument();
|
|
67
|
+
expect(screen.getByText('Go to previous page')).toBeInTheDocument();
|
|
68
|
+
expect(screen.getByText('Go to next page')).toBeInTheDocument();
|
|
69
|
+
expect(screen.getByText('Go to last page')).toBeInTheDocument();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('renders number input for page navigation', () => {
|
|
73
|
+
renderWithContext(<PaginationControls totalPages={5} />);
|
|
74
|
+
const numberInput = screen.getByLabelText('Current page');
|
|
75
|
+
expect(numberInput).toBeInTheDocument();
|
|
76
|
+
expect(numberInput).toHaveValue('1');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test('uses totalPages prop when provided', () => {
|
|
80
|
+
renderWithContext(<PaginationControls totalPages={20} />);
|
|
81
|
+
const numberInput = screen.getByLabelText('Current page');
|
|
82
|
+
expect(numberInput).toHaveAttribute('max', '20');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test('uses gridApi paginationGetTotalPages when totalPages prop is not provided', () => {
|
|
86
|
+
const mockGridApi = createMockGridApi({
|
|
87
|
+
paginationGetTotalPages: vi.fn(() => 10),
|
|
88
|
+
});
|
|
89
|
+
renderWithContext(<PaginationControls />, mockGridApi as GridApi);
|
|
90
|
+
const numberInput = screen.getByLabelText('Current page');
|
|
91
|
+
expect(numberInput).toHaveAttribute('max', '10');
|
|
92
|
+
expect(mockGridApi.paginationGetTotalPages).toHaveBeenCalled();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test('defaults to 0 total pages when neither prop nor gridApi is provided', () => {
|
|
96
|
+
renderWithContext(<PaginationControls />, null);
|
|
97
|
+
const numberInput = screen.getByLabelText('Current page');
|
|
98
|
+
expect(numberInput).toHaveAttribute('max', '1');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('calls onPageChange when provided and first page button is clicked', async () => {
|
|
102
|
+
const onPageChange = vi.fn();
|
|
103
|
+
renderWithContext(
|
|
104
|
+
<PaginationControls totalPages={5} onPageChange={onPageChange} />,
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
// navigate to second page
|
|
108
|
+
const nextButton = screen.getByText('Go to next page');
|
|
109
|
+
await userEvent.click(nextButton);
|
|
110
|
+
onPageChange.mockClear();
|
|
111
|
+
|
|
112
|
+
const firstPageButton = screen.getByText('Go to first page');
|
|
113
|
+
await userEvent.click(firstPageButton);
|
|
114
|
+
expect(onPageChange).toHaveBeenCalledExactlyOnceWith(0); // page is zero-indexed
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('calls gridApi.paginationGoToPage when onPageChange is not provided', async () => {
|
|
118
|
+
const mockGridApi = createMockGridApi();
|
|
119
|
+
renderWithContext(<PaginationControls totalPages={5} />, mockGridApi as GridApi);
|
|
120
|
+
const nextPageButton = screen.getByText('Go to next page');
|
|
121
|
+
await userEvent.click(nextPageButton);
|
|
122
|
+
expect(mockGridApi.paginationGoToPage).toHaveBeenCalledExactlyOnceWith(1); // page 2 (1-indexed) becomes 1 (0-indexed)
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test('navigates to next or previous page when next or previous button is clicked', async () => {
|
|
126
|
+
const onPageChange = vi.fn();
|
|
127
|
+
renderWithContext(
|
|
128
|
+
<PaginationControls totalPages={5} onPageChange={onPageChange} />,
|
|
129
|
+
);
|
|
130
|
+
const nextPageButton = screen.getByText('Go to next page');
|
|
131
|
+
await userEvent.click(nextPageButton);
|
|
132
|
+
expect(onPageChange).toHaveBeenCalledExactlyOnceWith(1);
|
|
133
|
+
|
|
134
|
+
onPageChange.mockClear();
|
|
135
|
+
|
|
136
|
+
const prevPageButton = screen.getByText('Go to previous page');
|
|
137
|
+
await userEvent.click(prevPageButton);
|
|
138
|
+
expect(onPageChange).toHaveBeenCalledExactlyOnceWith(0);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test('navigates to next page when next button is clicked', async () => {
|
|
142
|
+
const onPageChange = vi.fn();
|
|
143
|
+
renderWithContext(
|
|
144
|
+
<PaginationControls totalPages={5} onPageChange={onPageChange} />,
|
|
145
|
+
);
|
|
146
|
+
const nextPageButton = screen.getByText('Go to next page');
|
|
147
|
+
await userEvent.click(nextPageButton);
|
|
148
|
+
expect(onPageChange).toHaveBeenCalledExactlyOnceWith(1);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test('navigates to last page when last page button is clicked', async () => {
|
|
152
|
+
const onPageChange = vi.fn();
|
|
153
|
+
renderWithContext(
|
|
154
|
+
<PaginationControls totalPages={5} onPageChange={onPageChange} />,
|
|
155
|
+
);
|
|
156
|
+
const lastPageButton = screen.getByText('Go to last page');
|
|
157
|
+
await userEvent.click(lastPageButton);
|
|
158
|
+
expect(onPageChange).toHaveBeenCalledExactlyOnceWith(4); // page 5 (1-indexed) becomes 4 (0-indexed)
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test('updates input value when navigating via buttons', async () => {
|
|
162
|
+
const onPageChange = vi.fn();
|
|
163
|
+
renderWithContext(
|
|
164
|
+
<PaginationControls totalPages={5} onPageChange={onPageChange} />,
|
|
165
|
+
);
|
|
166
|
+
const numberInput = screen.getByLabelText('Current page');
|
|
167
|
+
const nextPageButton = screen.getByText('Go to next page');
|
|
168
|
+
|
|
169
|
+
expect(numberInput).toHaveValue('1');
|
|
170
|
+
await userEvent.click(nextPageButton);
|
|
171
|
+
expect(numberInput).toHaveValue('2');
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test('navigates to page when number input value changes', async () => {
|
|
175
|
+
const onPageChange = vi.fn();
|
|
176
|
+
renderWithContext(
|
|
177
|
+
<PaginationControls totalPages={5} onPageChange={onPageChange} />,
|
|
178
|
+
);
|
|
179
|
+
const numberInput = screen.getByLabelText('Current page');
|
|
180
|
+
|
|
181
|
+
await userEvent.clear(numberInput);
|
|
182
|
+
await userEvent.type(numberInput, '3');
|
|
183
|
+
await userEvent.tab(); // Trigger onChange
|
|
184
|
+
|
|
185
|
+
expect(onPageChange).toHaveBeenCalledExactlyOnceWith(2); // page 3 (1-indexed) becomes 2 (0-indexed)
|
|
186
|
+
expect(numberInput).toHaveValue('3');
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// TODO sort this out when we decide how number input handles inputs outside its min/max range
|
|
190
|
+
test.skip('does not navigate when number input value is 0 or negative', async () => {
|
|
191
|
+
const onPageChange = vi.fn();
|
|
192
|
+
renderWithContext(
|
|
193
|
+
<PaginationControls totalPages={5} onPageChange={onPageChange} />,
|
|
194
|
+
);
|
|
195
|
+
const numberInput = screen.getByLabelText('Current page');
|
|
196
|
+
|
|
197
|
+
await userEvent.clear(numberInput);
|
|
198
|
+
await userEvent.type(numberInput, '0');
|
|
199
|
+
await userEvent.tab();
|
|
200
|
+
|
|
201
|
+
// Should not call onPageChange for invalid values
|
|
202
|
+
expect(onPageChange).not.toHaveBeenCalled();
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
test('disables first and previous buttons on page 1', () => {
|
|
206
|
+
renderWithContext(<PaginationControls totalPages={5} />);
|
|
207
|
+
const firstPageButton = screen.getByText('Go to first page');
|
|
208
|
+
const prevPageButton = screen.getByText('Go to previous page');
|
|
209
|
+
|
|
210
|
+
expect(firstPageButton.parentElement).toBeDisabled();
|
|
211
|
+
expect(prevPageButton.parentElement).toBeDisabled();
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
test('disables next and last buttons on last page', async () => {
|
|
215
|
+
const onPageChange = vi.fn();
|
|
216
|
+
renderWithContext(
|
|
217
|
+
<PaginationControls totalPages={5} onPageChange={onPageChange} />,
|
|
218
|
+
);
|
|
219
|
+
const lastPageButton = screen.getByText('Go to last page');
|
|
220
|
+
const nextPageButton = screen.getByText('Go to next page');
|
|
221
|
+
|
|
222
|
+
// Navigate to last page
|
|
223
|
+
await userEvent.click(lastPageButton);
|
|
224
|
+
|
|
225
|
+
expect(nextPageButton.parentElement).toBeDisabled();
|
|
226
|
+
expect(lastPageButton.parentElement).toBeDisabled();
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
test('enables all buttons on middle pages', async () => {
|
|
230
|
+
const onPageChange = vi.fn();
|
|
231
|
+
renderWithContext(
|
|
232
|
+
<PaginationControls totalPages={5} onPageChange={onPageChange} />,
|
|
233
|
+
);
|
|
234
|
+
const numberInput = screen.getByLabelText('Current page');
|
|
235
|
+
|
|
236
|
+
// Navigate to page 3
|
|
237
|
+
await userEvent.clear(numberInput);
|
|
238
|
+
await userEvent.type(numberInput, '3');
|
|
239
|
+
await userEvent.tab();
|
|
240
|
+
|
|
241
|
+
const firstPageButton = screen.getByText('Go to first page');
|
|
242
|
+
const prevPageButton = screen.getByText('Go to previous page');
|
|
243
|
+
const nextPageButton = screen.getByText('Go to next page');
|
|
244
|
+
const lastPageButton = screen.getByText('Go to last page');
|
|
245
|
+
|
|
246
|
+
expect(firstPageButton).not.toBeDisabled();
|
|
247
|
+
expect(prevPageButton).not.toBeDisabled();
|
|
248
|
+
expect(nextPageButton).not.toBeDisabled();
|
|
249
|
+
expect(lastPageButton).not.toBeDisabled();
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
test('prefers totalPages prop over gridApi when both are provided', () => {
|
|
253
|
+
const mockGridApi = createMockGridApi();
|
|
254
|
+
renderWithContext(
|
|
255
|
+
<PaginationControls totalPages={15} />,
|
|
256
|
+
mockGridApi as GridApi,
|
|
257
|
+
);
|
|
258
|
+
const numberInput = screen.getByLabelText('Current page');
|
|
259
|
+
expect(numberInput).toHaveAttribute('max', '15');
|
|
260
|
+
// gridApi.paginationGetTotalPages should not be called when prop is provided
|
|
261
|
+
expect(mockGridApi.paginationGetTotalPages).not.toHaveBeenCalled();
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
test('handles single page scenario correctly', () => {
|
|
265
|
+
renderWithContext(<PaginationControls totalPages={1} />);
|
|
266
|
+
const firstPageButton = screen.getByText('Go to first page');
|
|
267
|
+
const prevPageButton = screen.getByText('Go to previous page');
|
|
268
|
+
const nextPageButton = screen.getByText('Go to next page');
|
|
269
|
+
const lastPageButton = screen.getByText('Go to last page');
|
|
270
|
+
|
|
271
|
+
expect(screen.getByLabelText('Current page')).toHaveValue('1');
|
|
272
|
+
|
|
273
|
+
expect(firstPageButton.parentElement).toBeDisabled();
|
|
274
|
+
expect(prevPageButton.parentElement).toBeDisabled();
|
|
275
|
+
expect(nextPageButton.parentElement).toBeDisabled();
|
|
276
|
+
expect(lastPageButton.parentElement).toBeDisabled();
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
describe('RowCountInfo', () => {
|
|
281
|
+
const renderWithContext = (
|
|
282
|
+
component: React.ReactElement,
|
|
283
|
+
gridApi: Partial<GridApi> | null = null,
|
|
284
|
+
) => {
|
|
285
|
+
return render(
|
|
286
|
+
<GridApiContext.Provider value={gridApi as GridApi | null}>
|
|
287
|
+
{component}
|
|
288
|
+
</GridApiContext.Provider>,
|
|
289
|
+
);
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
beforeEach(() => {
|
|
293
|
+
vi.clearAllMocks();
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
test('renders no message when no gridApi is provided', () => {
|
|
297
|
+
renderWithContext(<RowCountInfo />, null);
|
|
298
|
+
expect(screen.queryByText(/Showing \d+ results/)).not.toBeInTheDocument();
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
test('renders message with displayed count and totalRows when totalRows prop is provided', async () => {
|
|
302
|
+
const mockGridApi = createMockGridApi({
|
|
303
|
+
paginationGetTotalPages: vi.fn(() => 5),
|
|
304
|
+
paginationGetRowCount: vi.fn(() => 50),
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
renderWithContext(<RowCountInfo totalRows={100} />, mockGridApi as GridApi);
|
|
308
|
+
await waitFor(() => {
|
|
309
|
+
expect(screen.getByText(/Showing \d+ of 100 results/)).toBeInTheDocument();
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
test('displays correct count when gridApi is ready with single page', async () => {
|
|
314
|
+
const mockGridApi = createMockGridApi({
|
|
315
|
+
getDisplayedRowCount: vi.fn(() => 5),
|
|
316
|
+
paginationGetPageSize: vi.fn(() => 10),
|
|
317
|
+
paginationGetCurrentPage: vi.fn(() => 0),
|
|
318
|
+
paginationGetTotalPages: vi.fn(() => 1),
|
|
319
|
+
});
|
|
320
|
+
renderWithContext(<RowCountInfo />, mockGridApi as GridApi);
|
|
321
|
+
|
|
322
|
+
await waitFor(() => {
|
|
323
|
+
expect(screen.getByText('Showing 5 results')).toBeInTheDocument();
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
test('displays correct count when gridApi is ready with multiple pages', async () => {
|
|
328
|
+
const mockGridApi = createMockGridApi({
|
|
329
|
+
getDisplayedRowCount: vi.fn(() => 10),
|
|
330
|
+
paginationGetPageSize: vi.fn(() => 10),
|
|
331
|
+
paginationGetCurrentPage: vi.fn(() => 0),
|
|
332
|
+
paginationGetTotalPages: vi.fn(() => 5),
|
|
333
|
+
paginationGetRowCount: vi.fn(() => 50),
|
|
334
|
+
});
|
|
335
|
+
renderWithContext(<RowCountInfo />, mockGridApi as GridApi);
|
|
336
|
+
|
|
337
|
+
await waitFor(() => {
|
|
338
|
+
expect(screen.getByText('Showing 10 of 50 results')).toBeInTheDocument();
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
test('displays correct count on last page with remainder', async () => {
|
|
343
|
+
const mockGridApi = createMockGridApi({
|
|
344
|
+
getDisplayedRowCount: vi.fn(() => 7),
|
|
345
|
+
paginationGetPageSize: vi.fn(() => 10),
|
|
346
|
+
paginationGetCurrentPage: vi.fn(() => 4), // page 5 (0-indexed)
|
|
347
|
+
paginationGetTotalPages: vi.fn(() => 5),
|
|
348
|
+
paginationGetRowCount: vi.fn(() => 47),
|
|
349
|
+
});
|
|
350
|
+
renderWithContext(<RowCountInfo />, mockGridApi as GridApi);
|
|
351
|
+
|
|
352
|
+
await waitFor(() => {
|
|
353
|
+
expect(screen.getByText('Showing 7 of 47 results')).toBeInTheDocument();
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
test('displays correct count on last page when displayed count equals page size', async () => {
|
|
358
|
+
const mockGridApi = createMockGridApi({
|
|
359
|
+
getDisplayedRowCount: vi.fn(() => 10),
|
|
360
|
+
paginationGetPageSize: vi.fn(() => 10),
|
|
361
|
+
paginationGetCurrentPage: vi.fn(() => 4), // page 5 (0-indexed)
|
|
362
|
+
paginationGetTotalPages: vi.fn(() => 5),
|
|
363
|
+
paginationGetRowCount: vi.fn(() => 50),
|
|
364
|
+
});
|
|
365
|
+
renderWithContext(<RowCountInfo />, mockGridApi as GridApi);
|
|
366
|
+
|
|
367
|
+
await waitFor(() => {
|
|
368
|
+
expect(screen.getByText('Showing 10 of 50 results')).toBeInTheDocument();
|
|
369
|
+
});
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
test('displays correct count when displayed count is less than page size on non-last page', async () => {
|
|
373
|
+
const mockGridApi = createMockGridApi({
|
|
374
|
+
getDisplayedRowCount: vi.fn(() => 5),
|
|
375
|
+
paginationGetPageSize: vi.fn(() => 10),
|
|
376
|
+
paginationGetCurrentPage: vi.fn(() => 0),
|
|
377
|
+
paginationGetTotalPages: vi.fn(() => 3),
|
|
378
|
+
paginationGetRowCount: vi.fn(() => 25),
|
|
379
|
+
});
|
|
380
|
+
renderWithContext(<RowCountInfo />, mockGridApi as GridApi);
|
|
381
|
+
|
|
382
|
+
await waitFor(() => {
|
|
383
|
+
expect(screen.getByText('Showing 5 of 25 results')).toBeInTheDocument();
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
test('registers event listeners for paginationChanged, filterChanged, and rowDataUpdated', async () => {
|
|
388
|
+
const mockGridApi = createMockGridApi();
|
|
389
|
+
renderWithContext(<RowCountInfo />, mockGridApi as GridApi);
|
|
390
|
+
|
|
391
|
+
await waitFor(() => {
|
|
392
|
+
expect(mockGridApi.addEventListener).toHaveBeenCalledWith('paginationChanged', expect.any(Function));
|
|
393
|
+
expect(mockGridApi.addEventListener).toHaveBeenCalledWith('filterChanged', expect.any(Function));
|
|
394
|
+
expect(mockGridApi.addEventListener).toHaveBeenCalledWith('rowDataUpdated', expect.any(Function));
|
|
395
|
+
});
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
test('updates displayed count when paginationChanged event is triggered', async () => {
|
|
399
|
+
const mockGridApi = createMockGridApi({
|
|
400
|
+
getDisplayedRowCount: vi.fn(() => 10),
|
|
401
|
+
paginationGetPageSize: vi.fn(() => 10),
|
|
402
|
+
paginationGetCurrentPage: vi.fn(() => 0),
|
|
403
|
+
paginationGetTotalPages: vi.fn(() => 2),
|
|
404
|
+
paginationGetRowCount: vi.fn(() => 20),
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
renderWithContext(<RowCountInfo />, mockGridApi as GridApi);
|
|
408
|
+
|
|
409
|
+
await waitFor(() => {
|
|
410
|
+
expect(screen.getByText('Showing 10 of 20 results')).toBeInTheDocument();
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
// Update the mock to return different values
|
|
414
|
+
(mockGridApi.getDisplayedRowCount as ReturnType<typeof vi.fn>).mockReturnValue(5);
|
|
415
|
+
(mockGridApi.paginationGetCurrentPage as ReturnType<typeof vi.fn>).mockReturnValue(1);
|
|
416
|
+
|
|
417
|
+
// Trigger paginationChanged event
|
|
418
|
+
const evtName = 'paginationChanged' as unknown as AgEvent<string>;
|
|
419
|
+
mockGridApi?.dispatchEvent?.(evtName);
|
|
420
|
+
|
|
421
|
+
await waitFor(() => {
|
|
422
|
+
expect(screen.getByText('Showing 5 of 20 results')).toBeInTheDocument();
|
|
423
|
+
});
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
test('updates displayed count when filterChanged event is triggered', async () => {
|
|
427
|
+
const mockGridApi = createMockGridApi();
|
|
428
|
+
|
|
429
|
+
renderWithContext(<RowCountInfo />, mockGridApi as GridApi);
|
|
430
|
+
|
|
431
|
+
await waitFor(() => {
|
|
432
|
+
expect(screen.getByText('Showing 10 results')).toBeInTheDocument();
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
// Update the mock to return different values
|
|
436
|
+
(mockGridApi.getDisplayedRowCount as ReturnType<typeof vi.fn>).mockReturnValue(3);
|
|
437
|
+
|
|
438
|
+
// Trigger filterChanged event
|
|
439
|
+
const evtName = 'filterChanged' as unknown as AgEvent<string>;
|
|
440
|
+
mockGridApi?.dispatchEvent?.(evtName);
|
|
441
|
+
|
|
442
|
+
await waitFor(() => {
|
|
443
|
+
expect(screen.getByText('Showing 3 results')).toBeInTheDocument();
|
|
444
|
+
});
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
test('updates displayed count when rowDataUpdated event is triggered', async () => {
|
|
448
|
+
const mockGridApi = createMockGridApi();
|
|
449
|
+
|
|
450
|
+
renderWithContext(<RowCountInfo />, mockGridApi as GridApi);
|
|
451
|
+
|
|
452
|
+
await waitFor(() => {
|
|
453
|
+
expect(screen.getByText('Showing 10 results')).toBeInTheDocument();
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
// Update the mock to return different values
|
|
457
|
+
(mockGridApi.getDisplayedRowCount as ReturnType<typeof vi.fn>).mockReturnValue(8);
|
|
458
|
+
// Trigger rowDataUpdated event
|
|
459
|
+
const evtName = 'rowDataUpdated' as unknown as AgEvent<string>;
|
|
460
|
+
mockGridApi?.dispatchEvent?.(evtName);
|
|
461
|
+
|
|
462
|
+
await waitFor(() => {
|
|
463
|
+
expect(screen.getByText('Showing 8 results')).toBeInTheDocument();
|
|
464
|
+
});
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
test('handles case when displayedRowCount is undefined', async () => {
|
|
468
|
+
const mockGridApi = createMockGridApi({
|
|
469
|
+
getDisplayedRowCount: vi.fn(() => 0),
|
|
470
|
+
paginationGetPageSize: vi.fn(() => 10),
|
|
471
|
+
paginationGetCurrentPage: vi.fn(() => 0),
|
|
472
|
+
paginationGetTotalPages: vi.fn(() => 1),
|
|
473
|
+
});
|
|
474
|
+
renderWithContext(<RowCountInfo />, mockGridApi as GridApi);
|
|
475
|
+
|
|
476
|
+
await waitFor(() => {
|
|
477
|
+
// Should show a message, but the count might be -Infinity or NaN
|
|
478
|
+
expect(screen.getByText(/Showing .* results/)).toBeInTheDocument();
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
test('handles case when pageSize is undefined', async () => {
|
|
483
|
+
const mockGridApi = createMockGridApi({
|
|
484
|
+
getDisplayedRowCount: vi.fn(() => 10),
|
|
485
|
+
paginationGetPageSize: vi.fn(() => 0),
|
|
486
|
+
paginationGetCurrentPage: vi.fn(() => 0),
|
|
487
|
+
paginationGetTotalPages: vi.fn(() => 1),
|
|
488
|
+
});
|
|
489
|
+
renderWithContext(<RowCountInfo />, mockGridApi as GridApi);
|
|
490
|
+
|
|
491
|
+
await waitFor(() => {
|
|
492
|
+
expect(screen.getByText(/Showing .* results/)).toBeInTheDocument();
|
|
493
|
+
});
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
test('does not show totalRows when pagination has only one page and totalRows prop is not provided', async () => {
|
|
497
|
+
const mockGridApi = createMockGridApi({
|
|
498
|
+
getDisplayedRowCount: vi.fn(() => 5),
|
|
499
|
+
paginationGetPageSize: vi.fn(() => 10),
|
|
500
|
+
paginationGetCurrentPage: vi.fn(() => 0),
|
|
501
|
+
paginationGetTotalPages: vi.fn(() => 1),
|
|
502
|
+
paginationGetRowCount: vi.fn(() => 5),
|
|
503
|
+
});
|
|
504
|
+
renderWithContext(<RowCountInfo />, mockGridApi as GridApi);
|
|
505
|
+
|
|
506
|
+
await waitFor(() => {
|
|
507
|
+
expect(screen.getByText('Showing 5 results')).toBeInTheDocument();
|
|
508
|
+
expect(screen.queryByText(/of \d+ results/)).not.toBeInTheDocument();
|
|
509
|
+
});
|
|
510
|
+
});
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
describe('PageSizeSelector', () => {
|
|
514
|
+
const renderWithContext = (
|
|
515
|
+
component: React.ReactElement,
|
|
516
|
+
gridApi: Partial<GridApi> | null = null,
|
|
517
|
+
) => {
|
|
518
|
+
return render(
|
|
519
|
+
<GridApiContext.Provider value={gridApi as GridApi | null}>
|
|
520
|
+
{component}
|
|
521
|
+
</GridApiContext.Provider>,
|
|
522
|
+
);
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
beforeEach(() => {
|
|
526
|
+
vi.clearAllMocks();
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
test('renders with default page size of 100', () => {
|
|
530
|
+
renderWithContext(<PageSizeSelector />);
|
|
531
|
+
expect(screen.getByText('100')).toBeInTheDocument();
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
test('renders with initialPageSize prop', () => {
|
|
535
|
+
renderWithContext(<PageSizeSelector initialPageSize={50} />);
|
|
536
|
+
expect(screen.getByText('50')).toBeInTheDocument();
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
test('renders with initialPageSize of "All"', () => {
|
|
540
|
+
renderWithContext(<PageSizeSelector initialPageSize="All" />);
|
|
541
|
+
expect(screen.getByText('All')).toBeInTheDocument();
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
test('opens dropdown when trigger is clicked', async () => {
|
|
545
|
+
renderWithContext(<PageSizeSelector />);
|
|
546
|
+
const trigger = screen.getByText('100');
|
|
547
|
+
await userEvent.click(trigger);
|
|
548
|
+
expect(await screen.findByText('10')).toBeInTheDocument();
|
|
549
|
+
expect(screen.getByText('20')).toBeInTheDocument();
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
test('renders all default page sizes in dropdown', async () => {
|
|
553
|
+
renderWithContext(<PageSizeSelector />);
|
|
554
|
+
const trigger = screen.getByText('100');
|
|
555
|
+
await userEvent.click(trigger);
|
|
556
|
+
|
|
557
|
+
expect(await screen.findByText('10')).toBeInTheDocument();
|
|
558
|
+
expect(screen.getByText('20')).toBeInTheDocument();
|
|
559
|
+
expect(screen.getByText('30')).toBeInTheDocument();
|
|
560
|
+
expect(screen.getByText('50')).toBeInTheDocument();
|
|
561
|
+
expect(screen.getAllByText('100').length).toBe(2);
|
|
562
|
+
expect(screen.getByText('200')).toBeInTheDocument();
|
|
563
|
+
expect(screen.getByText('300')).toBeInTheDocument();
|
|
564
|
+
expect(screen.getByText('500')).toBeInTheDocument();
|
|
565
|
+
expect(screen.getByText('1000')).toBeInTheDocument();
|
|
566
|
+
expect(screen.getByText('All')).toBeInTheDocument();
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
test('renders custom availableSizes', async () => {
|
|
570
|
+
renderWithContext(
|
|
571
|
+
<PageSizeSelector availableSizes={[5, 10, 25]} />,
|
|
572
|
+
);
|
|
573
|
+
const trigger = screen.getByText('100');
|
|
574
|
+
await userEvent.click(trigger);
|
|
575
|
+
|
|
576
|
+
expect(await screen.findByText('5')).toBeInTheDocument();
|
|
577
|
+
expect(screen.getByText('10')).toBeInTheDocument();
|
|
578
|
+
expect(screen.getByText('25')).toBeInTheDocument();
|
|
579
|
+
expect(screen.queryByText('20')).not.toBeInTheDocument();
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
test('calls onPageSizeChange when page size is selected', async () => {
|
|
583
|
+
const onPageSizeChange = vi.fn();
|
|
584
|
+
renderWithContext(
|
|
585
|
+
<PageSizeSelector onPageSizeChange={onPageSizeChange} />,
|
|
586
|
+
);
|
|
587
|
+
|
|
588
|
+
const trigger = screen.getByText('100');
|
|
589
|
+
await userEvent.click(trigger);
|
|
590
|
+
|
|
591
|
+
const item = await screen.findByText('50');
|
|
592
|
+
await userEvent.click(item);
|
|
593
|
+
|
|
594
|
+
expect(onPageSizeChange).toHaveBeenCalledExactlyOnceWith(50);
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
test('updates displayed page size when selection changes', async () => {
|
|
598
|
+
renderWithContext(<PageSizeSelector />);
|
|
599
|
+
|
|
600
|
+
const trigger = screen.getByText('100');
|
|
601
|
+
await userEvent.click(trigger);
|
|
602
|
+
|
|
603
|
+
const item = await screen.findByText('20');
|
|
604
|
+
await userEvent.click(item);
|
|
605
|
+
|
|
606
|
+
await waitFor(() => {
|
|
607
|
+
expect(screen.getByText('20')).toBeInTheDocument();
|
|
608
|
+
});
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
test('calls gridApi.setGridOption with pagination true and paginationPageSize when number is selected', async () => {
|
|
612
|
+
const mockGridApi = createMockGridApi({
|
|
613
|
+
setGridOption: vi.fn(),
|
|
614
|
+
});
|
|
615
|
+
renderWithContext(<PageSizeSelector />, mockGridApi as GridApi);
|
|
616
|
+
|
|
617
|
+
const trigger = screen.getByText('100');
|
|
618
|
+
await userEvent.click(trigger);
|
|
619
|
+
|
|
620
|
+
const item = await screen.findByText('50');
|
|
621
|
+
await userEvent.click(item);
|
|
622
|
+
|
|
623
|
+
await waitFor(() => {
|
|
624
|
+
expect(mockGridApi.setGridOption).toHaveBeenCalledWith('pagination', true);
|
|
625
|
+
expect(mockGridApi.setGridOption).toHaveBeenCalledWith('paginationPageSize', 50);
|
|
626
|
+
});
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
test('calls gridApi.setGridOption with pagination false when "All" is selected', async () => {
|
|
630
|
+
const mockGridApi = createMockGridApi({
|
|
631
|
+
setGridOption: vi.fn(),
|
|
632
|
+
});
|
|
633
|
+
renderWithContext(<PageSizeSelector />, mockGridApi as GridApi);
|
|
634
|
+
|
|
635
|
+
const trigger = screen.getByText('100');
|
|
636
|
+
await userEvent.click(trigger);
|
|
637
|
+
|
|
638
|
+
const item = await screen.findByText('All');
|
|
639
|
+
await userEvent.click(item);
|
|
640
|
+
|
|
641
|
+
await waitFor(() => {
|
|
642
|
+
expect(mockGridApi.setGridOption).toHaveBeenCalledWith('pagination', false);
|
|
643
|
+
});
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
test('handles "All" option in onPageSizeChange callback', async () => {
|
|
647
|
+
const onPageSizeChange = vi.fn();
|
|
648
|
+
renderWithContext(
|
|
649
|
+
<PageSizeSelector onPageSizeChange={onPageSizeChange} />,
|
|
650
|
+
);
|
|
651
|
+
|
|
652
|
+
const trigger = screen.getByText('100');
|
|
653
|
+
await userEvent.click(trigger);
|
|
654
|
+
|
|
655
|
+
const item = await screen.findByText('All');
|
|
656
|
+
await userEvent.click(item);
|
|
657
|
+
|
|
658
|
+
expect(onPageSizeChange).toHaveBeenCalledExactlyOnceWith('All');
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
test('updates page size when initialPageSize is provided and gridApi is ready', async () => {
|
|
662
|
+
const mockGridApi = createMockGridApi({
|
|
663
|
+
setGridOption: vi.fn(),
|
|
664
|
+
});
|
|
665
|
+
renderWithContext(
|
|
666
|
+
<PageSizeSelector initialPageSize={25} />,
|
|
667
|
+
mockGridApi as GridApi,
|
|
668
|
+
);
|
|
669
|
+
|
|
670
|
+
await waitFor(() => {
|
|
671
|
+
expect(mockGridApi.setGridOption).toHaveBeenCalledWith('pagination', true);
|
|
672
|
+
expect(mockGridApi.setGridOption).toHaveBeenCalledWith('paginationPageSize', 25);
|
|
673
|
+
});
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
test('does not update gridApi when initialPageSize is "All" and gridApi is ready', async () => {
|
|
677
|
+
const mockGridApi = createMockGridApi({
|
|
678
|
+
setGridOption: vi.fn(),
|
|
679
|
+
});
|
|
680
|
+
renderWithContext(
|
|
681
|
+
<PageSizeSelector initialPageSize="All" />,
|
|
682
|
+
mockGridApi as GridApi,
|
|
683
|
+
);
|
|
684
|
+
|
|
685
|
+
await waitFor(() => {
|
|
686
|
+
expect(mockGridApi.setGridOption).toHaveBeenCalledWith('pagination', false);
|
|
687
|
+
});
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
test('does not call gridApi methods when gridApi is not available', async () => {
|
|
691
|
+
const onPageSizeChange = vi.fn();
|
|
692
|
+
renderWithContext(
|
|
693
|
+
<PageSizeSelector onPageSizeChange={onPageSizeChange} />,
|
|
694
|
+
null,
|
|
695
|
+
);
|
|
696
|
+
|
|
697
|
+
const trigger = screen.getByText('100');
|
|
698
|
+
await userEvent.click(trigger);
|
|
699
|
+
|
|
700
|
+
const item = await screen.findByText('50');
|
|
701
|
+
await userEvent.click(item);
|
|
702
|
+
|
|
703
|
+
expect(onPageSizeChange).toHaveBeenCalledExactlyOnceWith(50);
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
test('normalizes string numbers to numbers when updating page size', async () => {
|
|
707
|
+
const mockGridApi = createMockGridApi({
|
|
708
|
+
setGridOption: vi.fn(),
|
|
709
|
+
});
|
|
710
|
+
renderWithContext(
|
|
711
|
+
<PageSizeSelector />,
|
|
712
|
+
mockGridApi as GridApi,
|
|
713
|
+
);
|
|
714
|
+
|
|
715
|
+
const trigger = screen.getByLabelText('Select page size');
|
|
716
|
+
await userEvent.click(trigger);
|
|
717
|
+
|
|
718
|
+
// Click on a numeric option - it should be normalized to a number
|
|
719
|
+
const item = await screen.findByText('10');
|
|
720
|
+
await userEvent.click(item);
|
|
721
|
+
|
|
722
|
+
expect(mockGridApi.setGridOption).toHaveBeenCalledWith('paginationPageSize', 10);
|
|
723
|
+
});
|
|
724
|
+
|
|
725
|
+
test('handles custom availableSizes with "All" option', async () => {
|
|
726
|
+
const onPageSizeChange = vi.fn();
|
|
727
|
+
renderWithContext(
|
|
728
|
+
<PageSizeSelector
|
|
729
|
+
availableSizes={[15, 30, 'All']}
|
|
730
|
+
onPageSizeChange={onPageSizeChange}
|
|
731
|
+
/>,
|
|
732
|
+
);
|
|
733
|
+
|
|
734
|
+
const trigger = screen.getByText('100');
|
|
735
|
+
await userEvent.click(trigger);
|
|
736
|
+
|
|
737
|
+
expect(await screen.findByText('15')).toBeInTheDocument();
|
|
738
|
+
expect(screen.getByText('30')).toBeInTheDocument();
|
|
739
|
+
expect(screen.getByText('All')).toBeInTheDocument();
|
|
740
|
+
|
|
741
|
+
const allItem = screen.getByText('All');
|
|
742
|
+
await userEvent.click(allItem);
|
|
743
|
+
|
|
744
|
+
expect(onPageSizeChange).toHaveBeenCalledExactlyOnceWith('All');
|
|
745
|
+
});
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
describe('PaginationPanel', () => {
|
|
749
|
+
const renderWithContext = (
|
|
750
|
+
component: React.ReactElement,
|
|
751
|
+
gridApi: Partial<GridApi> = createMockGridApi({
|
|
752
|
+
getDisplayedRowCount: vi.fn(() => 10),
|
|
753
|
+
paginationGetPageSize: vi.fn(() => 10),
|
|
754
|
+
paginationGetCurrentPage: vi.fn(() => 0),
|
|
755
|
+
paginationGetTotalPages: vi.fn(() => 5),
|
|
756
|
+
paginationGetRowCount: vi.fn(() => 50),
|
|
757
|
+
setGridOption: vi.fn(),
|
|
758
|
+
}),
|
|
759
|
+
) => {
|
|
760
|
+
return render(
|
|
761
|
+
<GridApiContext.Provider value={gridApi as GridApi | null}>
|
|
762
|
+
{component}
|
|
763
|
+
</GridApiContext.Provider>,
|
|
764
|
+
);
|
|
765
|
+
};
|
|
766
|
+
|
|
767
|
+
beforeEach(() => {
|
|
768
|
+
vi.clearAllMocks();
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
test('renders correctly', () => {
|
|
772
|
+
const { container } = renderWithContext(
|
|
773
|
+
<PaginationPanel />,
|
|
774
|
+
);
|
|
775
|
+
const nav = container.querySelector('nav[aria-label="Pagination"]');
|
|
776
|
+
expect(nav).toBeInTheDocument();
|
|
777
|
+
expect(nav).toHaveClass('ds-table__pagination-panel');
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
test('renders the pagination components', async () => {
|
|
781
|
+
renderWithContext(
|
|
782
|
+
<PaginationPanel />,
|
|
783
|
+
);
|
|
784
|
+
await waitFor(() => {
|
|
785
|
+
expect(screen.getByText(/Showing \d+ of \d+ results/)).toBeInTheDocument();
|
|
786
|
+
|
|
787
|
+
expect(screen.getByText('Go to first page')).toBeInTheDocument();
|
|
788
|
+
expect(screen.getByText('Go to previous page')).toBeInTheDocument();
|
|
789
|
+
expect(screen.getByText('Go to next page')).toBeInTheDocument();
|
|
790
|
+
expect(screen.getByText('Go to last page')).toBeInTheDocument();
|
|
791
|
+
|
|
792
|
+
expect(screen.getByLabelText('Select page size')).toBeInTheDocument();
|
|
793
|
+
});
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
test('passes props to RowCountInfo', async () => {
|
|
797
|
+
renderWithContext(
|
|
798
|
+
<PaginationPanel
|
|
799
|
+
totalRows={100}
|
|
800
|
+
/>,
|
|
801
|
+
);
|
|
802
|
+
await waitFor(() => {
|
|
803
|
+
expect(screen.getByText(/Showing \d+ of 100 results/)).toBeInTheDocument();
|
|
804
|
+
});
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
test('passes props to PaginationControls', async () => {
|
|
808
|
+
const onPageChange = vi.fn();
|
|
809
|
+
|
|
810
|
+
renderWithContext(
|
|
811
|
+
<PaginationPanel
|
|
812
|
+
totalPages={20}
|
|
813
|
+
onPageChange={onPageChange}
|
|
814
|
+
/>,
|
|
815
|
+
);
|
|
816
|
+
const numberInput = screen.getByLabelText('Current page');
|
|
817
|
+
expect(numberInput).toHaveAttribute('max', '20');
|
|
818
|
+
const nextPageButton = screen.getByText('Go to next page');
|
|
819
|
+
await userEvent.click(nextPageButton);
|
|
820
|
+
expect(onPageChange).toHaveBeenCalledExactlyOnceWith(1);
|
|
821
|
+
});
|
|
822
|
+
|
|
823
|
+
test('passes props to PageSizeSelector', async () => {
|
|
824
|
+
const onPageSizeChange = vi.fn();
|
|
825
|
+
|
|
826
|
+
renderWithContext(
|
|
827
|
+
<PaginationPanel
|
|
828
|
+
availableSizes={[5, 15, 25]}
|
|
829
|
+
initialPageSize={5}
|
|
830
|
+
onPageSizeChange={onPageSizeChange}
|
|
831
|
+
/>,
|
|
832
|
+
);
|
|
833
|
+
|
|
834
|
+
const trigger = screen.getByLabelText('Select page size');
|
|
835
|
+
expect(trigger.textContent).toContain('5');
|
|
836
|
+
await userEvent.click(trigger);
|
|
837
|
+
expect(await screen.findByText('15')).toBeInTheDocument();
|
|
838
|
+
expect(screen.getAllByText('5').length).toBe(2);
|
|
839
|
+
expect(screen.getByText('15')).toBeInTheDocument();
|
|
840
|
+
const item = await screen.findByText('25');
|
|
841
|
+
expect(item).toBeInTheDocument();
|
|
842
|
+
await userEvent.click(item);
|
|
843
|
+
expect(onPageSizeChange).toHaveBeenLastCalledWith(25);
|
|
844
|
+
});
|
|
845
|
+
});
|
|
846
|
+
});
|