uikit-react-public 0.37.0 → 0.37.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/dist/components/Pagination/Pagination.stories.d.ts +1 -0
- package/dist/components/Pagination/PaginationControls.d.ts +2 -1
- package/dist/components/Pagination/__tests__/PaginationControls.test.d.ts +1 -0
- package/dist/components/Pagination/subcomponents/PaginationCompactControls.d.ts +7 -0
- package/dist/components/Pagination/subcomponents/PaginationStandardControls.d.ts +8 -0
- package/dist/components/Pagination/subcomponents/index.d.ts +2 -0
- package/dist/index.js +4626 -4445
- package/lib/components/Pagination/Pagination.stories.tsx +9 -0
- package/lib/components/Pagination/PaginationControls.tsx +17 -245
- package/lib/components/Pagination/__tests__/PaginationControls.test.tsx +213 -0
- package/lib/components/Pagination/subcomponents/PaginationCompactControls.tsx +266 -0
- package/lib/components/Pagination/subcomponents/PaginationStandardControls.tsx +246 -0
- package/lib/components/Pagination/subcomponents/index.ts +2 -0
- package/package.json +5 -5
|
@@ -44,6 +44,15 @@ export const FewPages: Story = {
|
|
|
44
44
|
},
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
+
export const Compact: Story = {
|
|
48
|
+
args: {
|
|
49
|
+
offset: 0,
|
|
50
|
+
limit: 20,
|
|
51
|
+
total: 60,
|
|
52
|
+
children: <Pagination.Controls variant='compact' />,
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
|
|
47
56
|
export const ItemsInfo: Story = {
|
|
48
57
|
args: {
|
|
49
58
|
offset: 60,
|
|
@@ -1,262 +1,34 @@
|
|
|
1
|
-
import { HTMLAttributes, memo
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import getPaginationButtons from './getPaginationButtons';
|
|
7
|
-
import { useMediaQuery } from '../../hooks';
|
|
1
|
+
import { HTMLAttributes, memo } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
PaginationCompactControls,
|
|
4
|
+
PaginationStandardControls,
|
|
5
|
+
} from './subcomponents';
|
|
8
6
|
|
|
9
7
|
export const NAME = 'ucl-ukit-pagination__controls';
|
|
10
8
|
export const DEFAULT_MAX_BUTTONS = 9;
|
|
11
9
|
|
|
12
10
|
export interface PaginationControlsProps extends HTMLAttributes<HTMLDivElement> {
|
|
11
|
+
variant?: 'default' | 'compact';
|
|
13
12
|
maxNumberButtons?: number;
|
|
14
13
|
testId?: string;
|
|
15
14
|
}
|
|
16
15
|
|
|
17
16
|
const PaginationControls = ({
|
|
17
|
+
variant = 'default',
|
|
18
18
|
maxNumberButtons = DEFAULT_MAX_BUTTONS,
|
|
19
19
|
testId = NAME,
|
|
20
20
|
className,
|
|
21
|
+
...props
|
|
21
22
|
}: PaginationControlsProps) => {
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
(newPage: number) => {
|
|
32
|
-
if (contextValue) {
|
|
33
|
-
const { mode, limit, onPageChange, currentPage, trackedMaxPage } =
|
|
34
|
-
contextValue;
|
|
35
|
-
|
|
36
|
-
if (mode === 'tracked') {
|
|
37
|
-
if (
|
|
38
|
-
newPage < 1 ||
|
|
39
|
-
newPage > trackedMaxPage ||
|
|
40
|
-
newPage === currentPage
|
|
41
|
-
) {
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
if (onPageChange) {
|
|
45
|
-
onPageChange(newPage);
|
|
46
|
-
}
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const newOffset = (newPage - 1) * limit;
|
|
51
|
-
if (onPageChange) {
|
|
52
|
-
onPageChange(newOffset);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
[contextValue]
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
if (!contextValue) {
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const {
|
|
64
|
-
mode,
|
|
65
|
-
limit,
|
|
66
|
-
total,
|
|
67
|
-
currentPage,
|
|
68
|
-
trackedMaxPage,
|
|
69
|
-
hasPreviousPage,
|
|
70
|
-
hasNextPage,
|
|
71
|
-
onNextPage,
|
|
72
|
-
onPreviousPage,
|
|
73
|
-
} = contextValue;
|
|
74
|
-
|
|
75
|
-
const totalPages =
|
|
76
|
-
typeof total === 'number' ? Math.ceil(total / limit) : undefined;
|
|
77
|
-
|
|
78
|
-
const paginationButtons =
|
|
79
|
-
mode === 'tracked'
|
|
80
|
-
? Array.from({ length: trackedMaxPage }, (_, i) => i + 1)
|
|
81
|
-
: getPaginationButtons(
|
|
82
|
-
currentPage,
|
|
83
|
-
totalPages ?? 0,
|
|
84
|
-
isTabletPlus ? maxNumberButtons : 5
|
|
85
|
-
);
|
|
86
|
-
|
|
87
|
-
const baseStyle = css``;
|
|
88
|
-
|
|
89
|
-
const style = cx(NAME, baseStyle, className);
|
|
90
|
-
|
|
91
|
-
const listStyle = css`
|
|
92
|
-
margin: 0;
|
|
93
|
-
padding: 0;
|
|
94
|
-
display: flex;
|
|
95
|
-
justify-content: center;
|
|
96
|
-
align-items: center;
|
|
97
|
-
list-style: none;
|
|
98
|
-
gap: ${theme.margin.m4};
|
|
99
|
-
flex-wrap: nowrap;
|
|
100
|
-
|
|
101
|
-
@media (min-width: ${theme.breakpoints.tablet}px) {
|
|
102
|
-
gap: ${theme.margin.m8};
|
|
103
|
-
}
|
|
104
|
-
`;
|
|
105
|
-
|
|
106
|
-
const buttonBaseStyle = css`
|
|
107
|
-
@media (max-width: ${theme.breakpoints.tablet}px) {
|
|
108
|
-
gap: ${theme.margin.m4};
|
|
109
|
-
}
|
|
110
|
-
`;
|
|
111
|
-
|
|
112
|
-
const previousButtonStyle = cx(
|
|
113
|
-
buttonBaseStyle,
|
|
114
|
-
css`
|
|
115
|
-
margin-right: ${theme.margin.m16};
|
|
116
|
-
display: none;
|
|
117
|
-
|
|
118
|
-
@media (min-width: ${theme.breakpoints.tablet}px) {
|
|
119
|
-
display: inline-block;
|
|
120
|
-
}
|
|
121
|
-
`
|
|
122
|
-
);
|
|
123
|
-
|
|
124
|
-
const nextButtonStyle = cx(
|
|
125
|
-
buttonBaseStyle,
|
|
126
|
-
css`
|
|
127
|
-
margin-left: ${theme.margin.m16};
|
|
128
|
-
display: none;
|
|
129
|
-
|
|
130
|
-
@media (min-width: ${theme.breakpoints.tablet}px) {
|
|
131
|
-
display: inline-block;
|
|
132
|
-
}
|
|
133
|
-
`
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
const pageNumberButtonBaseStyle = cx(
|
|
137
|
-
buttonBaseStyle,
|
|
138
|
-
css`
|
|
139
|
-
height: 40px;
|
|
140
|
-
min-width: 40px;
|
|
141
|
-
padding: 0;
|
|
142
|
-
|
|
143
|
-
@media (min-width: ${theme.breakpoints.tablet}px) {
|
|
144
|
-
height: 48px;
|
|
145
|
-
min-width: 48px;
|
|
146
|
-
}
|
|
147
|
-
`
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
const pageNumberButtonStyle = cx(
|
|
151
|
-
pageNumberButtonBaseStyle,
|
|
152
|
-
css`
|
|
153
|
-
border: none;
|
|
154
|
-
color: ${theme.colour.text.secondary};
|
|
155
|
-
`
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
const currentPageNumberButtonStyle = cx(
|
|
159
|
-
pageNumberButtonBaseStyle,
|
|
160
|
-
css`
|
|
161
|
-
color: ${theme.colour.text.brand};
|
|
162
|
-
border-color: ${theme.colour.border.brand};
|
|
163
|
-
`
|
|
164
|
-
);
|
|
165
|
-
|
|
166
|
-
const buttonNumberLabelStyle = css`
|
|
167
|
-
padding: 0 ${theme.padding.p8};
|
|
168
|
-
`;
|
|
169
|
-
|
|
170
|
-
return (
|
|
171
|
-
<nav
|
|
172
|
-
className={style}
|
|
173
|
-
aria-label={
|
|
174
|
-
typeof totalPages === 'number'
|
|
175
|
-
? `Pagination, ${totalPages} pages total`
|
|
176
|
-
: 'Pagination'
|
|
177
|
-
}
|
|
178
|
-
data-testid={testId}
|
|
179
|
-
>
|
|
180
|
-
<ul className={listStyle}>
|
|
181
|
-
<li>
|
|
182
|
-
<Button
|
|
183
|
-
className={previousButtonStyle}
|
|
184
|
-
variant='tertiary'
|
|
185
|
-
size={isTabletPlus ? 'default' : 'small'}
|
|
186
|
-
aria-label='Go to previous page'
|
|
187
|
-
onClick={() => {
|
|
188
|
-
if (mode === 'tracked') {
|
|
189
|
-
if (onPreviousPage) {
|
|
190
|
-
onPreviousPage();
|
|
191
|
-
} else {
|
|
192
|
-
handlePageChange(currentPage - 1);
|
|
193
|
-
}
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
handlePageChange(currentPage - 1);
|
|
197
|
-
}}
|
|
198
|
-
disabled={!hasPreviousPage}
|
|
199
|
-
>
|
|
200
|
-
Previous
|
|
201
|
-
</Button>
|
|
202
|
-
</li>
|
|
203
|
-
|
|
204
|
-
{paginationButtons.map((page) => (
|
|
205
|
-
<li key={page}>
|
|
206
|
-
{page === '...1' || page === '...2' ? (
|
|
207
|
-
<span aria-hidden>...</span>
|
|
208
|
-
) : (
|
|
209
|
-
<>
|
|
210
|
-
{page !== currentPage && (
|
|
211
|
-
<Button
|
|
212
|
-
className={pageNumberButtonStyle}
|
|
213
|
-
variant='secondary'
|
|
214
|
-
size={isTabletPlus ? 'default' : 'small'}
|
|
215
|
-
aria-label={`Page ${page}`}
|
|
216
|
-
onClick={() => handlePageChange(page)}
|
|
217
|
-
>
|
|
218
|
-
<span className={buttonNumberLabelStyle}>{page}</span>
|
|
219
|
-
</Button>
|
|
220
|
-
)}
|
|
221
|
-
{page === currentPage && (
|
|
222
|
-
<Button
|
|
223
|
-
className={currentPageNumberButtonStyle}
|
|
224
|
-
variant='secondary'
|
|
225
|
-
size={isTabletPlus ? 'default' : 'small'}
|
|
226
|
-
aria-label={`Page ${page}, current page`}
|
|
227
|
-
aria-current='page'
|
|
228
|
-
disabled
|
|
229
|
-
onClick={() => handlePageChange(page)}
|
|
230
|
-
>
|
|
231
|
-
<span className={buttonNumberLabelStyle}>{page}</span>
|
|
232
|
-
</Button>
|
|
233
|
-
)}
|
|
234
|
-
</>
|
|
235
|
-
)}
|
|
236
|
-
</li>
|
|
237
|
-
))}
|
|
238
|
-
|
|
239
|
-
<li>
|
|
240
|
-
<Button
|
|
241
|
-
className={nextButtonStyle}
|
|
242
|
-
variant='tertiary'
|
|
243
|
-
aria-label='Go to next page'
|
|
244
|
-
onClick={() => {
|
|
245
|
-
if (mode === 'tracked') {
|
|
246
|
-
if (onNextPage) {
|
|
247
|
-
onNextPage();
|
|
248
|
-
}
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
handlePageChange(currentPage + 1);
|
|
252
|
-
}}
|
|
253
|
-
disabled={!hasNextPage}
|
|
254
|
-
>
|
|
255
|
-
Next
|
|
256
|
-
</Button>
|
|
257
|
-
</li>
|
|
258
|
-
</ul>
|
|
259
|
-
</nav>
|
|
23
|
+
const controlsProps = { ...props, className, name: NAME, testId };
|
|
24
|
+
|
|
25
|
+
return variant === 'compact' ? (
|
|
26
|
+
<PaginationCompactControls {...controlsProps} />
|
|
27
|
+
) : (
|
|
28
|
+
<PaginationStandardControls
|
|
29
|
+
{...controlsProps}
|
|
30
|
+
maxNumberButtons={maxNumberButtons}
|
|
31
|
+
/>
|
|
260
32
|
);
|
|
261
33
|
};
|
|
262
34
|
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { describe, expect, test, vi } from 'vitest';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import { useState } from 'react';
|
|
5
|
+
import { ThemeContextProvider } from '../../../theme';
|
|
6
|
+
import announce from '../../../utils/announce';
|
|
7
|
+
import Pagination from '..';
|
|
8
|
+
|
|
9
|
+
vi.mock('../../../utils/announce');
|
|
10
|
+
|
|
11
|
+
const renderPagination = (
|
|
12
|
+
props: Partial<React.ComponentProps<typeof Pagination>> = {},
|
|
13
|
+
controlsProps: React.ComponentProps<typeof Pagination.Controls> = {
|
|
14
|
+
variant: 'compact',
|
|
15
|
+
}
|
|
16
|
+
) =>
|
|
17
|
+
render(
|
|
18
|
+
<ThemeContextProvider>
|
|
19
|
+
<Pagination
|
|
20
|
+
offset={20}
|
|
21
|
+
limit={20}
|
|
22
|
+
total={60}
|
|
23
|
+
{...props}
|
|
24
|
+
>
|
|
25
|
+
<Pagination.Controls {...controlsProps} />
|
|
26
|
+
</Pagination>
|
|
27
|
+
</ThemeContextProvider>
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
describe('PaginationControls', () => {
|
|
31
|
+
test.each(['default', 'compact'] as const)(
|
|
32
|
+
'forwards HTML attributes to the %s controls',
|
|
33
|
+
(variant) => {
|
|
34
|
+
renderPagination({}, { variant, title: `${variant} controls` });
|
|
35
|
+
|
|
36
|
+
expect(screen.getByTitle(`${variant} controls`)).toBeInTheDocument();
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
test('renders compact pagination controls', () => {
|
|
41
|
+
renderPagination();
|
|
42
|
+
|
|
43
|
+
expect(
|
|
44
|
+
screen.getByRole('button', { name: 'Go to previous page' })
|
|
45
|
+
).toBeEnabled();
|
|
46
|
+
expect(screen.getByRole('textbox', { name: 'Page number' })).toHaveValue(
|
|
47
|
+
'2'
|
|
48
|
+
);
|
|
49
|
+
expect(
|
|
50
|
+
screen.getByRole('textbox', { name: 'Page number' })
|
|
51
|
+
).toHaveAccessibleDescription(
|
|
52
|
+
'Page 2 of 3. Enter a page number and press Enter.'
|
|
53
|
+
);
|
|
54
|
+
expect(screen.getByText('of 3')).toBeInTheDocument();
|
|
55
|
+
expect(
|
|
56
|
+
screen.getByRole('button', { name: 'Go to next page' })
|
|
57
|
+
).toBeEnabled();
|
|
58
|
+
expect(screen.queryByRole('button', { name: 'Page 1' })).toBeNull();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('changes page using compact controls', async () => {
|
|
62
|
+
const user = userEvent.setup();
|
|
63
|
+
const onPageChange = vi.fn();
|
|
64
|
+
|
|
65
|
+
const ControlledPagination = () => {
|
|
66
|
+
const [offset, setOffset] = useState(20);
|
|
67
|
+
|
|
68
|
+
const handlePageChange = (newOffset: number) => {
|
|
69
|
+
onPageChange(newOffset);
|
|
70
|
+
setOffset(newOffset);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<ThemeContextProvider>
|
|
75
|
+
<Pagination
|
|
76
|
+
offset={offset}
|
|
77
|
+
limit={20}
|
|
78
|
+
total={60}
|
|
79
|
+
onPageChange={handlePageChange}
|
|
80
|
+
>
|
|
81
|
+
<Pagination.Controls variant='compact' />
|
|
82
|
+
</Pagination>
|
|
83
|
+
</ThemeContextProvider>
|
|
84
|
+
);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
render(<ControlledPagination />);
|
|
88
|
+
|
|
89
|
+
await user.click(
|
|
90
|
+
screen.getByRole('button', { name: 'Go to previous page' })
|
|
91
|
+
);
|
|
92
|
+
expect(screen.getByRole('textbox', { name: 'Page number' })).toHaveValue(
|
|
93
|
+
'1'
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
await user.click(screen.getByRole('button', { name: 'Go to next page' }));
|
|
97
|
+
expect(screen.getByRole('textbox', { name: 'Page number' })).toHaveValue(
|
|
98
|
+
'2'
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
expect(onPageChange).toHaveBeenNthCalledWith(1, 0);
|
|
102
|
+
expect(onPageChange).toHaveBeenNthCalledWith(2, 20);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('changes page when a page number is entered', async () => {
|
|
106
|
+
const user = userEvent.setup();
|
|
107
|
+
const onPageChange = vi.fn();
|
|
108
|
+
renderPagination({ offset: 0, total: 100, onPageChange });
|
|
109
|
+
|
|
110
|
+
const currentPageInput = screen.getByRole('textbox', {
|
|
111
|
+
name: 'Page number',
|
|
112
|
+
});
|
|
113
|
+
await user.clear(currentPageInput);
|
|
114
|
+
await user.type(currentPageInput, '4{Enter}');
|
|
115
|
+
|
|
116
|
+
expect(onPageChange).toHaveBeenCalledWith(60);
|
|
117
|
+
expect(currentPageInput).not.toHaveFocus();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('does not change page when the entered page is out of range', async () => {
|
|
121
|
+
const user = userEvent.setup();
|
|
122
|
+
const onPageChange = vi.fn();
|
|
123
|
+
renderPagination({ offset: 0, onPageChange });
|
|
124
|
+
|
|
125
|
+
const currentPageInput = screen.getByRole('textbox', {
|
|
126
|
+
name: 'Page number',
|
|
127
|
+
});
|
|
128
|
+
await user.clear(currentPageInput);
|
|
129
|
+
await user.type(currentPageInput, '4{Enter}');
|
|
130
|
+
|
|
131
|
+
expect(onPageChange).not.toHaveBeenCalled();
|
|
132
|
+
expect(currentPageInput).toHaveValue('4');
|
|
133
|
+
expect(currentPageInput).toHaveFocus();
|
|
134
|
+
expect(currentPageInput).toHaveAttribute('aria-invalid', 'true');
|
|
135
|
+
expect(announce).toHaveBeenCalledWith(
|
|
136
|
+
'Enter a page number from 1 to 3.',
|
|
137
|
+
true
|
|
138
|
+
);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test('does not change page when the entered value contains non-digits', async () => {
|
|
142
|
+
const user = userEvent.setup();
|
|
143
|
+
const onPageChange = vi.fn();
|
|
144
|
+
renderPagination({ offset: 0, total: 2000, onPageChange });
|
|
145
|
+
|
|
146
|
+
const currentPageInput = screen.getByRole('textbox', {
|
|
147
|
+
name: 'Page number',
|
|
148
|
+
});
|
|
149
|
+
await user.clear(currentPageInput);
|
|
150
|
+
await user.type(currentPageInput, '1e2{Enter}');
|
|
151
|
+
|
|
152
|
+
expect(onPageChange).not.toHaveBeenCalled();
|
|
153
|
+
expect(currentPageInput).toHaveAttribute('aria-invalid', 'true');
|
|
154
|
+
expect(announce).toHaveBeenCalledWith(
|
|
155
|
+
'Enter a page number from 1 to 100.',
|
|
156
|
+
true
|
|
157
|
+
);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test('cancels the entered page and exits the input on Escape', async () => {
|
|
161
|
+
const user = userEvent.setup();
|
|
162
|
+
const onPageChange = vi.fn();
|
|
163
|
+
renderPagination({ onPageChange });
|
|
164
|
+
|
|
165
|
+
const currentPageInput = screen.getByRole('textbox', {
|
|
166
|
+
name: 'Page number',
|
|
167
|
+
});
|
|
168
|
+
await user.clear(currentPageInput);
|
|
169
|
+
await user.type(currentPageInput, '3{Escape}');
|
|
170
|
+
|
|
171
|
+
expect(onPageChange).not.toHaveBeenCalled();
|
|
172
|
+
expect(currentPageInput).toHaveValue('2');
|
|
173
|
+
expect(currentPageInput).not.toHaveFocus();
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test('cancels the entered page when the input loses focus', async () => {
|
|
177
|
+
const user = userEvent.setup();
|
|
178
|
+
const onPageChange = vi.fn();
|
|
179
|
+
renderPagination({ onPageChange });
|
|
180
|
+
|
|
181
|
+
const currentPageInput = screen.getByRole('textbox', {
|
|
182
|
+
name: 'Page number',
|
|
183
|
+
});
|
|
184
|
+
await user.clear(currentPageInput);
|
|
185
|
+
await user.type(currentPageInput, '3');
|
|
186
|
+
await user.tab();
|
|
187
|
+
|
|
188
|
+
expect(onPageChange).not.toHaveBeenCalled();
|
|
189
|
+
expect(currentPageInput).toHaveValue('2');
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test('renders zero of zero when there are no pages', () => {
|
|
193
|
+
renderPagination({ offset: 0, total: 0 });
|
|
194
|
+
|
|
195
|
+
expect(
|
|
196
|
+
screen.getByRole('navigation', { name: 'Pagination, 0 pages total' })
|
|
197
|
+
).toBeInTheDocument();
|
|
198
|
+
expect(screen.getByRole('textbox', { name: 'Page number' })).toHaveValue(
|
|
199
|
+
'0'
|
|
200
|
+
);
|
|
201
|
+
expect(screen.getByRole('textbox', { name: 'Page number' })).toBeDisabled();
|
|
202
|
+
expect(
|
|
203
|
+
screen.getByRole('textbox', { name: 'Page number' })
|
|
204
|
+
).toHaveAccessibleDescription('Page 0 of 0.');
|
|
205
|
+
expect(screen.getByText('of 0')).toBeInTheDocument();
|
|
206
|
+
expect(
|
|
207
|
+
screen.getByRole('button', { name: 'Go to previous page' })
|
|
208
|
+
).toBeDisabled();
|
|
209
|
+
expect(
|
|
210
|
+
screen.getByRole('button', { name: 'Go to next page' })
|
|
211
|
+
).toBeDisabled();
|
|
212
|
+
});
|
|
213
|
+
});
|