Skip to content

Commit b53537b

Browse files
authored
[PRMP-828] Review Journey UI Only (#919)
1 parent 3c63231 commit b53537b

File tree

66 files changed

+9132
-255
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+9132
-255
lines changed
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
import { render, screen, waitFor } from '@testing-library/react';
2+
import userEvent from '@testing-library/user-event';
3+
import { afterEach, beforeEach, describe, expect, it, vi, Mock } from 'vitest';
4+
import ReviewDetailsAddMoreChoicePage from './ReviewDetailsAddMoreChoicePage';
5+
import { runAxeTest } from '../../../../helpers/test/axeTestHelper';
6+
import { getConfigForDocType } from '../../../../helpers/utils/documentType';
7+
8+
vi.mock('../../../../helpers/utils/documentType');
9+
10+
const mockNavigate = vi.fn();
11+
const mockReviewId = 'test-review-123';
12+
13+
vi.mock('react-router-dom', async (): Promise<unknown> => {
14+
const actual = await vi.importActual('react-router-dom');
15+
return {
16+
...actual,
17+
useNavigate: (): Mock => mockNavigate,
18+
useParams: (): { reviewId: string } => ({ reviewId: mockReviewId }),
19+
};
20+
});
21+
22+
const mockgetConfigForDocType = getConfigForDocType as Mock;
23+
24+
describe('ReviewDetailsAddMoreChoicePage', () => {
25+
const testReviewSnoMed = '16521000000101';
26+
const mockConfig = {
27+
displayName: 'Test Document Type',
28+
};
29+
30+
beforeEach(() => {
31+
vi.clearAllMocks();
32+
import.meta.env.VITE_ENVIRONMENT = 'vitest';
33+
mockgetConfigForDocType.mockReturnValue(mockConfig);
34+
});
35+
36+
afterEach(() => {
37+
vi.clearAllMocks();
38+
});
39+
40+
describe('Rendering', () => {
41+
it('renders the page heading correctly', () => {
42+
render(<ReviewDetailsAddMoreChoicePage reviewSnoMed={testReviewSnoMed} />);
43+
44+
expect(
45+
screen.getByRole('heading', {
46+
name: 'Do you want to add more files to this patients record?',
47+
}),
48+
).toBeInTheDocument();
49+
});
50+
51+
it('renders back button with correct text', () => {
52+
render(<ReviewDetailsAddMoreChoicePage reviewSnoMed={testReviewSnoMed} />);
53+
54+
expect(screen.getByText('Go back')).toBeInTheDocument();
55+
});
56+
57+
it('renders both radio button options', () => {
58+
render(<ReviewDetailsAddMoreChoicePage reviewSnoMed={testReviewSnoMed} />);
59+
60+
const yesRadio = screen.getByRole('radio', {
61+
name: /Yes I have more scanned paper records to add for this patient/i,
62+
});
63+
const noRadio = screen.getByRole('radio', {
64+
name: /No, I don't have anymore scanned paper records to add for this patient/i,
65+
});
66+
67+
expect(yesRadio).toBeInTheDocument();
68+
expect(noRadio).toBeInTheDocument();
69+
expect(yesRadio).not.toBeChecked();
70+
expect(noRadio).not.toBeChecked();
71+
});
72+
73+
it('renders continue button', () => {
74+
render(<ReviewDetailsAddMoreChoicePage reviewSnoMed={testReviewSnoMed} />);
75+
76+
expect(screen.getByRole('button', { name: 'Continue' })).toBeInTheDocument();
77+
});
78+
79+
it('does not show error message initially', () => {
80+
render(<ReviewDetailsAddMoreChoicePage reviewSnoMed={testReviewSnoMed} />);
81+
82+
expect(screen.queryByText('Select an option')).not.toBeInTheDocument();
83+
});
84+
});
85+
86+
describe('Error Handling', () => {
87+
it('displays error message when continue is clicked without selection', async () => {
88+
render(<ReviewDetailsAddMoreChoicePage reviewSnoMed={testReviewSnoMed} />);
89+
90+
const continueButton = screen.getByRole('button', { name: 'Continue' });
91+
await userEvent.click(continueButton);
92+
93+
await waitFor(() => {
94+
expect(screen.getByText('Select an option')).toBeInTheDocument();
95+
});
96+
});
97+
98+
it('does not navigate when no selection is made', async () => {
99+
render(<ReviewDetailsAddMoreChoicePage reviewSnoMed={testReviewSnoMed} />);
100+
101+
const continueButton = screen.getByRole('button', { name: 'Continue' });
102+
await userEvent.click(continueButton);
103+
104+
await waitFor(() => {
105+
expect(screen.getByText('Select an option')).toBeInTheDocument();
106+
});
107+
expect(mockNavigate).not.toHaveBeenCalled();
108+
});
109+
110+
it('clears error message when yes radio button is selected', async () => {
111+
render(<ReviewDetailsAddMoreChoicePage reviewSnoMed={testReviewSnoMed} />);
112+
113+
const continueButton = screen.getByRole('button', { name: 'Continue' });
114+
await userEvent.click(continueButton);
115+
116+
await waitFor(() => {
117+
expect(screen.getByText('Select an option')).toBeInTheDocument();
118+
});
119+
120+
const yesRadio = screen.getByRole('radio', {
121+
name: /Yes I have more scanned paper records to add for this patient/i,
122+
});
123+
await userEvent.click(yesRadio);
124+
125+
await waitFor(() => {
126+
expect(screen.queryByText('Select an option')).not.toBeInTheDocument();
127+
});
128+
});
129+
130+
it('clears error message when no radio button is selected', async () => {
131+
render(<ReviewDetailsAddMoreChoicePage reviewSnoMed={testReviewSnoMed} />);
132+
133+
const continueButton = screen.getByRole('button', { name: 'Continue' });
134+
await userEvent.click(continueButton);
135+
136+
await waitFor(() => {
137+
expect(screen.getByText('Select an option')).toBeInTheDocument();
138+
});
139+
140+
const noRadio = screen.getByRole('radio', {
141+
name: /No, I don't have anymore scanned paper records to add for this patient/i,
142+
});
143+
await userEvent.click(noRadio);
144+
145+
await waitFor(() => {
146+
expect(screen.queryByText('Select an option')).not.toBeInTheDocument();
147+
});
148+
});
149+
});
150+
151+
describe('User Interactions', () => {
152+
it('allows selecting the yes radio button', async () => {
153+
render(<ReviewDetailsAddMoreChoicePage reviewSnoMed={testReviewSnoMed} />);
154+
155+
const yesRadio = screen.getByRole('radio', {
156+
name: /Yes I have more scanned paper records to add for this patient/i,
157+
});
158+
await userEvent.click(yesRadio);
159+
160+
await waitFor(() => {
161+
expect(yesRadio).toBeChecked();
162+
});
163+
});
164+
165+
it('allows selecting the no radio button', async () => {
166+
render(<ReviewDetailsAddMoreChoicePage reviewSnoMed={testReviewSnoMed} />);
167+
168+
const noRadio = screen.getByRole('radio', {
169+
name: /No, I don't have anymore scanned paper records to add for this patient/i,
170+
});
171+
await userEvent.click(noRadio);
172+
173+
await waitFor(() => {
174+
expect(noRadio).toBeChecked();
175+
});
176+
});
177+
178+
it('allows changing selection from yes to no', async () => {
179+
render(<ReviewDetailsAddMoreChoicePage reviewSnoMed={testReviewSnoMed} />);
180+
181+
const yesRadio = screen.getByRole('radio', {
182+
name: /Yes I have more scanned paper records to add for this patient/i,
183+
});
184+
const noRadio = screen.getByRole('radio', {
185+
name: /No, I don't have anymore scanned paper records to add for this patient/i,
186+
});
187+
188+
await userEvent.click(yesRadio);
189+
await waitFor(() => {
190+
expect(yesRadio).toBeChecked();
191+
});
192+
193+
await userEvent.click(noRadio);
194+
await waitFor(() => {
195+
expect(noRadio).toBeChecked();
196+
expect(yesRadio).not.toBeChecked();
197+
});
198+
});
199+
200+
it('prevents default form submission', async () => {
201+
render(<ReviewDetailsAddMoreChoicePage reviewSnoMed={testReviewSnoMed} />);
202+
203+
const form = screen.getByRole('button', { name: 'Continue' }).closest('form');
204+
const submitHandler = vi.fn((e) => e.preventDefault());
205+
form?.addEventListener('submit', submitHandler);
206+
207+
const continueButton = screen.getByRole('button', { name: 'Continue' });
208+
await userEvent.click(continueButton);
209+
210+
expect(submitHandler).toHaveBeenCalled();
211+
});
212+
});
213+
214+
describe('Accessibility', () => {
215+
it('passes axe accessibility tests in initial state', async () => {
216+
const { container } = render(
217+
<ReviewDetailsAddMoreChoicePage reviewSnoMed={testReviewSnoMed} />,
218+
);
219+
220+
const results = await runAxeTest(container);
221+
expect(results).toHaveNoViolations();
222+
});
223+
224+
it('passes axe accessibility tests in error state', async () => {
225+
const { container } = render(
226+
<ReviewDetailsAddMoreChoicePage reviewSnoMed={testReviewSnoMed} />,
227+
);
228+
229+
const continueButton = screen.getByRole('button', { name: 'Continue' });
230+
await userEvent.click(continueButton);
231+
232+
await waitFor(() => {
233+
expect(screen.getByText('Select an option')).toBeInTheDocument();
234+
});
235+
236+
const results = await runAxeTest(container);
237+
expect(results).toHaveNoViolations();
238+
});
239+
240+
it('passes axe accessibility tests with radio button selected', async () => {
241+
const { container } = render(
242+
<ReviewDetailsAddMoreChoicePage reviewSnoMed={testReviewSnoMed} />,
243+
);
244+
245+
const yesRadio = screen.getByRole('radio', {
246+
name: /Yes I have more scanned paper records to add for this patient/i,
247+
});
248+
await userEvent.click(yesRadio);
249+
250+
await waitFor(() => {
251+
expect(yesRadio).toBeChecked();
252+
});
253+
254+
const results = await runAxeTest(container);
255+
expect(results).toHaveNoViolations();
256+
});
257+
});
258+
});
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import React, { useState } from 'react';
2+
import { Button, Fieldset, Radios } from 'nhsuk-react-components';
3+
import { useNavigate, useParams } from 'react-router-dom';
4+
import { navigateUrlParam, routeChildren } from '../../../../types/generic/routes';
5+
import BackButton from '../../../generic/backButton/BackButton';
6+
7+
type ReviewDetailsAddMoreChoicePageProps = {
8+
reviewSnoMed: string;
9+
};
10+
11+
type AddMoreChoice = 'yes' | 'no' | '';
12+
13+
const ReviewDetailsAddMoreChoicePage: React.FC<ReviewDetailsAddMoreChoicePageProps> = ({
14+
reviewSnoMed,
15+
}) => {
16+
const navigate = useNavigate();
17+
const [addMoreChoice, setAddMoreChoice] = useState<AddMoreChoice>('');
18+
const [showError, setShowError] = useState(false);
19+
const { reviewId } = useParams<{ reviewId: string }>();
20+
21+
const handleContinue = (): void => {
22+
if (!addMoreChoice || !reviewId) {
23+
setShowError(true);
24+
return;
25+
}
26+
27+
if (addMoreChoice === 'yes') {
28+
navigateUrlParam(
29+
routeChildren.ADMIN_REVIEW_UPLOAD_ADDITIONAL_FILES,
30+
{ reviewId },
31+
navigate,
32+
);
33+
} else {
34+
navigateUrlParam(routeChildren.ADMIN_REVIEW_UPLOAD_FILE_ORDER, { reviewId }, navigate);
35+
}
36+
};
37+
38+
return (
39+
<>
40+
<BackButton backLinkText="Go back" />
41+
42+
<form
43+
onSubmit={(e): void => {
44+
e.preventDefault();
45+
handleContinue();
46+
}}
47+
>
48+
<Fieldset>
49+
<Fieldset.Legend isPageHeading>
50+
Do you want to add more files to this patients record?
51+
</Fieldset.Legend>
52+
<Radios
53+
name="add-more-choice"
54+
id="add-more-choice"
55+
error={showError ? 'Select an option' : ''}
56+
>
57+
<Radios.Radio
58+
value="yes"
59+
id="yes-radio"
60+
data-testid="yes-radio-btn"
61+
onChange={(e: React.ChangeEvent<HTMLInputElement>): void => {
62+
setAddMoreChoice(e.target.value as AddMoreChoice);
63+
if (showError) {
64+
setShowError(false);
65+
}
66+
}}
67+
>
68+
Yes I have more scanned paper records to add for this patient
69+
</Radios.Radio>
70+
<Radios.Radio
71+
value="no"
72+
id="no-radio"
73+
data-testid="no-radio-btn"
74+
onChange={(e: React.ChangeEvent<HTMLInputElement>): void => {
75+
setAddMoreChoice(e.target.value as AddMoreChoice);
76+
if (showError) {
77+
setShowError(false);
78+
}
79+
}}
80+
>
81+
No, I don&apos;t have anymore scanned paper records to add for this
82+
patient
83+
</Radios.Radio>
84+
</Radios>
85+
</Fieldset>
86+
87+
<Button type="submit" id="continue-button" data-testid="continue-btn">
88+
Continue
89+
</Button>
90+
</form>
91+
</>
92+
);
93+
};
94+
95+
export default ReviewDetailsAddMoreChoicePage;

0 commit comments

Comments
 (0)