Skip to content

Commit 62dddf9

Browse files
committed
[PRMP-825]
1 parent 1280228 commit 62dddf9

File tree

4 files changed

+419
-19
lines changed

4 files changed

+419
-19
lines changed
Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
import { render, screen } from '@testing-library/react';
2+
import { FC } from 'react';
3+
import { Pagination, childIsOfComponentType } from './Pagination';
4+
import { PaginationLinkText } from './PaginationItem';
5+
6+
describe('Pagination', () => {
7+
it('renders the navigation element', () => {
8+
render(<Pagination />);
9+
expect(screen.getByRole('navigation')).toBeInTheDocument();
10+
});
11+
12+
it('renders with custom aria-label', () => {
13+
render(<Pagination aria-label="Custom Label" />);
14+
expect(screen.getByRole('navigation', { name: 'Custom Label' })).toBeInTheDocument();
15+
});
16+
17+
it('renders previous and next links correctly', () => {
18+
render(
19+
<Pagination>
20+
<Pagination.Link previous href="/prev">
21+
Previous
22+
</Pagination.Link>
23+
<Pagination.Link next href="/next">
24+
Next
25+
</Pagination.Link>
26+
</Pagination>,
27+
);
28+
29+
const prevLink = screen.getByRole('link', { name: /previous/i });
30+
const nextLink = screen.getByRole('link', { name: /next/i });
31+
32+
expect(prevLink).toBeInTheDocument();
33+
expect(nextLink).toBeInTheDocument();
34+
expect(prevLink).toHaveAttribute('href', '/prev');
35+
expect(nextLink).toHaveAttribute('href', '/next');
36+
});
37+
38+
it('renders numbered items in a list', () => {
39+
render(
40+
<Pagination>
41+
<Pagination.Item href="/1" number={1}>
42+
1
43+
</Pagination.Item>
44+
<Pagination.Item current href="/2" number={2}>
45+
2
46+
</Pagination.Item>
47+
<Pagination.Item href="/3" number={3}>
48+
3
49+
</Pagination.Item>
50+
</Pagination>,
51+
);
52+
53+
const list = screen.getByRole('list');
54+
expect(list).toBeInTheDocument();
55+
expect(list).toHaveClass('nhsuk-pagination__list');
56+
57+
const items = screen.getAllByRole('listitem');
58+
expect(items).toHaveLength(3);
59+
60+
// Check for current item
61+
const currentLink = screen.getByRole('link', { name: /page 2/i });
62+
expect(currentLink).toBeInTheDocument();
63+
// Note: The exact implementation of 'current' styling/aria might vary,
64+
// but usually it adds a class or aria-current.
65+
// Looking at PaginationItem.tsx:
66+
// if (rest.current) { itemClassName = `${itemClassName} ${className}--current`; }
67+
// It doesn't seem to add aria-current to the link automatically in PaginationItem,
68+
// but let's check if we can verify the class on the list item.
69+
70+
// We can find the list item that contains the current link
71+
const currentItem = items[1];
72+
expect(currentItem).toHaveClass('nhsuk-pagination__item--current');
73+
});
74+
75+
it('renders mixed content (previous, next, and items) correctly', () => {
76+
render(
77+
<Pagination>
78+
<Pagination.Link previous href="/prev">
79+
Previous
80+
</Pagination.Link>
81+
<Pagination.Item href="/1" number={1}>
82+
1
83+
</Pagination.Item>
84+
<Pagination.Item current href="/2" number={2}>
85+
2
86+
</Pagination.Item>
87+
<Pagination.Item href="/3" number={3}>
88+
3
89+
</Pagination.Item>
90+
<Pagination.Link next href="/next">
91+
Next
92+
</Pagination.Link>
93+
</Pagination>,
94+
);
95+
96+
const nav = screen.getByRole('navigation');
97+
expect(nav).toHaveClass('nhsuk-pagination--numbered');
98+
99+
const prevLink = screen.getByRole('link', { name: /previous/i });
100+
const nextLink = screen.getByRole('link', { name: /next/i });
101+
const list = screen.getByRole('list');
102+
103+
expect(nav).toContainElement(prevLink);
104+
expect(nav).toContainElement(list);
105+
expect(nav).toContainElement(nextLink);
106+
});
107+
108+
it('renders ellipsis item correctly', () => {
109+
render(
110+
<Pagination>
111+
<Pagination.Item ellipsis>...</Pagination.Item>
112+
</Pagination>,
113+
);
114+
115+
const items = screen.getAllByRole('listitem');
116+
expect(items).toHaveLength(1);
117+
expect(items[0]).toHaveClass('nhsuk-pagination__item--ellipsis');
118+
expect(items[0]).toHaveTextContent('⋯');
119+
});
120+
121+
it('renders previous item with correct classes (legacy)', () => {
122+
render(
123+
<Pagination>
124+
<Pagination.Item previous href="/prev">
125+
Previous
126+
</Pagination.Item>
127+
</Pagination>,
128+
);
129+
const item = screen.getByRole('listitem');
130+
expect(item).toHaveClass('nhsuk-pagination-item--previous');
131+
});
132+
133+
it('renders next item with correct classes (legacy)', () => {
134+
render(
135+
<Pagination>
136+
<Pagination.Item next href="/next">
137+
Next
138+
</Pagination.Item>
139+
</Pagination>,
140+
);
141+
const item = screen.getByRole('listitem');
142+
expect(item).toHaveClass('nhsuk-pagination-item--next');
143+
});
144+
145+
it('renders legacy pagination list correctly', () => {
146+
render(
147+
<Pagination>
148+
<Pagination.Item previous href="/prev">
149+
Previous
150+
</Pagination.Item>
151+
<Pagination.Item next href="/next">
152+
Next
153+
</Pagination.Item>
154+
</Pagination>,
155+
);
156+
157+
const list = screen.getByRole('list');
158+
expect(list).toHaveClass('nhsuk-list nhsuk-pagination__list');
159+
expect(list).not.toHaveClass('nhsuk-pagination__list--numbered');
160+
161+
const nav = screen.getByRole('navigation');
162+
expect(nav).not.toHaveClass('nhsuk-pagination--numbered');
163+
});
164+
165+
it('renders standard item when both previous and next are true', () => {
166+
render(
167+
<Pagination>
168+
{/* @ts-ignore - Testing edge case */}
169+
<Pagination.Item previous next href="/mixed">
170+
Mixed
171+
</Pagination.Item>
172+
</Pagination>,
173+
);
174+
const item = screen.getByRole('listitem');
175+
// Should not have previous or next classes
176+
expect(item).not.toHaveClass('nhsuk-pagination-item--previous');
177+
expect(item).not.toHaveClass('nhsuk-pagination-item--next');
178+
expect(item).toHaveClass('nhsuk-pagination__item');
179+
});
180+
181+
it('renders standard link correctly', () => {
182+
render(<Pagination.Link href="/link">Link</Pagination.Link>);
183+
const link = screen.getByRole('link', { name: /link/i });
184+
expect(link).toBeInTheDocument();
185+
expect(link).not.toHaveClass('nhsuk-pagination__previous');
186+
expect(link).not.toHaveClass('nhsuk-pagination__next');
187+
});
188+
189+
it('renders non-string children directly (legacy link)', () => {
190+
render(
191+
<Pagination.Link href="/legacy">
192+
<span>Icon</span>
193+
</Pagination.Link>,
194+
);
195+
const link = screen.getByRole('link');
196+
expect(link).toHaveTextContent('Icon');
197+
expect(link.querySelector('svg')).not.toBeInTheDocument();
198+
});
199+
200+
it('renders link with number prop correctly', () => {
201+
render(
202+
<Pagination.Link href="/1" number={1}>
203+
1
204+
</Pagination.Link>,
205+
);
206+
const link = screen.getByRole('link', { name: /page 1/i });
207+
expect(link).toBeInTheDocument();
208+
});
209+
});
210+
211+
describe('PaginationLinkText', () => {
212+
it('renders number when provided', () => {
213+
render(<PaginationLinkText number={5} />);
214+
expect(screen.getByText('5')).toBeInTheDocument();
215+
});
216+
217+
it('renders label text correctly', () => {
218+
render(
219+
<PaginationLinkText next labelText="Page 1">
220+
Title
221+
</PaginationLinkText>,
222+
);
223+
expect(screen.getByText('Title')).toBeInTheDocument();
224+
expect(screen.getByText('Page 1')).toBeInTheDocument();
225+
expect(screen.getByText(':')).toHaveClass('nhsuk-u-visually-hidden');
226+
});
227+
228+
it('renders default Previous text when no children provided', () => {
229+
render(<PaginationLinkText previous={true} />);
230+
expect(screen.getByText('Previous')).toBeInTheDocument();
231+
expect(screen.getByText('page')).toHaveClass('nhsuk-u-visually-hidden');
232+
});
233+
234+
it('renders default Next text when no children provided', () => {
235+
render(<PaginationLinkText next={true} />);
236+
expect(screen.getByText('Next')).toBeInTheDocument();
237+
expect(screen.getByText('page')).toHaveClass('nhsuk-u-visually-hidden');
238+
});
239+
240+
it('returns null for infinite number', () => {
241+
const { container } = render(<PaginationLinkText number={Infinity} />);
242+
expect(container).toBeEmptyDOMElement();
243+
});
244+
245+
it('renders children instead of default text when both provided', () => {
246+
render(<PaginationLinkText previous={true}>Custom Previous</PaginationLinkText>);
247+
expect(screen.getByText('Custom Previous')).toBeInTheDocument();
248+
});
249+
250+
it('renders nothing when no props provided', () => {
251+
const { container } = render(<PaginationLinkText />);
252+
expect(container).toBeEmptyDOMElement();
253+
});
254+
});
255+
256+
describe('childIsOfComponentType', () => {
257+
const TestComponent: FC<{ className?: string }> = () => <div>Test</div>;
258+
259+
it('returns false for invalid component', () => {
260+
expect(childIsOfComponentType(null, TestComponent)).toBe(false);
261+
expect(childIsOfComponentType('string', TestComponent)).toBe(false);
262+
});
263+
264+
it('returns true for matching component type', () => {
265+
const element = <TestComponent />;
266+
expect(childIsOfComponentType(element, TestComponent)).toBe(true);
267+
});
268+
269+
it('returns true for matching fallback className', () => {
270+
const element = <div className="test-class" />;
271+
// @ts-ignore - mocking a component check where type doesn't match but class does
272+
expect(childIsOfComponentType(element, TestComponent, { className: 'test-class' })).toBe(
273+
true,
274+
);
275+
});
276+
277+
it('returns false for non-matching fallback className', () => {
278+
const element = <div className="other-class" />;
279+
// @ts-ignore
280+
expect(childIsOfComponentType(element, TestComponent, { className: 'test-class' })).toBe(
281+
false,
282+
);
283+
});
284+
285+
it('returns false when fallback is not provided', () => {
286+
const element = <div className="test-class" />;
287+
// @ts-ignore
288+
expect(childIsOfComponentType(element, TestComponent)).toBe(false);
289+
});
290+
291+
it('returns false when child has no className', () => {
292+
const element = <div></div>;
293+
// @ts-ignore
294+
expect(childIsOfComponentType(element, TestComponent, { className: 'test-class' })).toBe(
295+
false,
296+
);
297+
});
298+
});

app/src/helpers/requests/getReviews.ts

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
import axios from 'axios';
22
import { endpoints } from '../../types/generic/endpoints';
33
import { ReviewsResponse } from '../../types/generic/reviews';
4-
import getMockResponses from '../test/getMockReviews';
4+
import getMockResponses, { setupMockRequest } from '../test/getMockReviews';
55
import { isLocal } from '../utils/isLocal';
66

7-
if (isLocal) {
8-
var testingCounter = 0;
9-
}
10-
117
const getReviews = async (
128
baseUrl: string,
139
nhsNumber: string,
@@ -23,20 +19,8 @@ const getReviews = async (
2319
});
2420

2521
if (isLocal) {
26-
testingCounter = testingCounter + 1;
27-
28-
// simulate data being added over time by setting this to true.
29-
const simulateDataAddition = false;
30-
if (simulateDataAddition && testingCounter > 10) {
31-
params.append('injectData', 'true');
32-
params.append('testingCounter', (testingCounter - 10).toString());
33-
}
34-
35-
if (!getMockResponses) {
36-
throw new Error('never should happen');
37-
}
38-
39-
return await getMockResponses(params);
22+
setupMockRequest!(params);
23+
return await getMockResponses!(params);
4024
}
4125

4226
const response = await axios.get<ReviewsResponse>(gatewayUrl + `?${params.toString()}`);

0 commit comments

Comments
 (0)