Skip to content

Commit e59ffa1

Browse files
authored
APPT-1971 Moving remaining components to be used from nhsuk-react-components (#1615)
# Description This PR is ensuring that Button, Checkbox and Radio components are being used from nhsuk-react-components library. It also fixes the jest test issue where jest is complaining that these 3 components use dynamic import. To get around the dynamic imports issue, we have global mock for Button, Checkbox and Radio components as we do not need to test those. The global mock can be found in setupTests.tsx file. It also converts Tabs component, and ensure horizontal button alignment. # Checklist: - [ ] My work is behind a feature toggle (if appropriate) - [ ] If my work is behind a feature toggle, I've added a full suite of tests for both the ON and OFF state - [ ] The ticket number is in the Pull Request title, with format "APPT-XXX: My Title Here" - [ ] I have ran npm tsc / lint (in the future these will be ran automatically) - [ ] My code generates no new .NET warnings (in the future these will be treated as errors) - [ ] If I've added a new Function, it is disabled in all but one of the terraform groups (e.g. http_functions) - [ ] If I've added a new Function, it has both unit and integration tests. Any request body validators have unit tests also - [ ] If I've made UI changes, I've added appropriate Playwright and Jest tests - [ ] If I've added/updated an end-point, I've added the appropriate annotations and tested the Swagger documentation reflects the change
1 parent 937c325 commit e59ffa1

62 files changed

Lines changed: 344 additions & 894 deletions

File tree

Some content is hidden

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

src/client/jest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const createJestConfig = nextJest({
77
/** @type {import('jest').Config} */
88
const config = {
99
collectCoverageFrom: ['src/**/*.{ts,tsx}', '!src/**/*.d.ts'],
10-
setupFilesAfterEnv: ['<rootDir>/setupTests.ts'],
10+
setupFilesAfterEnv: ['<rootDir>/setupTests.tsx'],
1111
testMatch: [
1212
'<rootDir>/src/**/*.(spec|test).{js,jsx,ts,tsx}',
1313
'<rootDir>/test/**/*.(spec|test).{js,jsx,ts,tsx}',

src/client/setupTests.ts

Lines changed: 0 additions & 6 deletions
This file was deleted.

src/client/setupTests.tsx

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import React from 'react';
2+
import '@testing-library/jest-dom';
3+
import { loadEnvConfig } from '@next/env';
4+
5+
loadEnvConfig(process.cwd());
6+
7+
jest.setTimeout(10000);
8+
9+
// Global mock for NHS UK React Components
10+
// This prevents "Experimental VM Modules" errors caused by
11+
// dynamic imports inside the library's Button and Radios components.
12+
/* eslint-disable @typescript-eslint/no-explicit-any, react/jsx-props-no-spreading */
13+
jest.mock('nhsuk-react-components', () => {
14+
const actual = jest.requireActual('nhsuk-react-components');
15+
16+
const MockRadios = ({ children, legend, error, ...props }: any) => (
17+
<div {...props}>
18+
{legend && <legend>{legend}</legend>}
19+
{error && <span className="nhsuk-error-message">{error}</span>}
20+
{children}
21+
</div>
22+
);
23+
24+
const MockRadiosItem = React.forwardRef(
25+
({ children, id, value, ...props }: any, ref: any) => (
26+
<div>
27+
<input type="radio" id={id} value={value} ref={ref} {...props} />
28+
<label htmlFor={id}>{children}</label>
29+
</div>
30+
),
31+
);
32+
33+
MockRadiosItem.displayName = 'MockRadiosItem';
34+
MockRadios.Item = MockRadiosItem;
35+
36+
const MockCheckboxes = ({ children, ...props }: any) => (
37+
<div {...props}>{children}</div>
38+
);
39+
40+
const MockCheckboxesItem = React.forwardRef(
41+
({ children, id, value, ...props }: any, ref: any) => (
42+
<div>
43+
<input
44+
type="checkbox"
45+
id={id}
46+
value={value}
47+
ref={ref}
48+
label={typeof children === 'string' ? children : undefined}
49+
{...props}
50+
/>
51+
<label htmlFor={id}>{children}</label>
52+
</div>
53+
),
54+
);
55+
MockCheckboxesItem.displayName = 'MockCheckboxesItem';
56+
MockCheckboxes.Item = MockCheckboxesItem;
57+
58+
return {
59+
...actual,
60+
Button: ({ children, warning, secondary: _, ...props }: any) => (
61+
<button {...props} data-warning={warning?.toString()}>
62+
{children}
63+
</button>
64+
),
65+
Radios: MockRadios,
66+
Checkboxes: MockCheckboxes,
67+
};
68+
});
69+
/* eslint-enable @typescript-eslint/no-explicit-any, react/jsx-props-no-spreading */

src/client/src/app/cookies-policy/cookie-consent-form.tsx

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
11
'use client';
22

3-
import {
4-
Button,
5-
FormGroup,
6-
Radio,
7-
RadioGroup,
8-
SmallSpinnerWithText,
9-
} from '@components/nhsuk-frontend';
3+
import { FormGroup, SmallSpinnerWithText } from '@components/nhsuk-frontend';
104
import { setCookieConsent } from '@services/cookiesService';
115
import { NhsMyaCookieConsent } from '@types';
126
import { useRouter } from 'next/navigation';
137
import { useTransition } from 'react';
148
import { SubmitHandler, useForm } from 'react-hook-form';
9+
import { Button, Radios } from 'nhsuk-react-components';
1510

1611
type CookieConsentFormProps = {
1712
consentCookie?: NhsMyaCookieConsent;
@@ -52,24 +47,20 @@ const CookieConsentForm = ({ consentCookie }: CookieConsentFormProps) => {
5247
legend="Tell us if we can use analytics cookies"
5348
error={errors.consented?.message}
5449
>
55-
<RadioGroup>
56-
<Radio
57-
label="Use cookies to measure my website use"
58-
id="consented-yes"
50+
<Radios>
51+
<Radios.Item
5952
value="yes"
53+
id="consented-yes"
6054
{...register('consented', {
61-
required: { value: true, message: 'Select an option' },
62-
})}
63-
/>
64-
<Radio
65-
label="Do not use cookies to measure my website use"
66-
id="consented-no"
67-
value="no"
68-
{...register('consented', {
69-
required: { value: true, message: 'Select an option' },
55+
required: 'Select an option',
7056
})}
71-
/>
72-
</RadioGroup>
57+
>
58+
Use cookies to measure my website use
59+
</Radios.Item>
60+
<Radios.Item value="no" id="consented-no" {...register('consented')}>
61+
Do not use cookies to measure my website use
62+
</Radios.Item>
63+
</Radios>
7364
</FormGroup>
7465
{pendingSubmit ? (
7566
<SmallSpinnerWithText text="Working..." />

src/client/src/app/eula/accept-eula-form.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
'use client';
2-
import { Button, SmallSpinnerWithText } from '@components/nhsuk-frontend';
2+
import { SmallSpinnerWithText } from '@components/nhsuk-frontend';
33
import { acceptEula } from '@services/appointmentsService';
44
import { EulaVersion } from '@types';
55
import { SubmitHandler, useForm } from 'react-hook-form';
66
import { useRouter } from 'next/navigation';
77
import { useTransition } from 'react';
88
import fromServer from '@server/fromServer';
9+
import { Button } from 'nhsuk-react-components';
910

1011
type AcceptEulaFormProps = {
1112
eulaVersion: EulaVersion;

src/client/src/app/lib/components/nhsuk-frontend/button-group.test.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Button, ButtonGroup } from '@nhsuk-frontend-components';
1+
import { ButtonGroup } from '@nhsuk-frontend-components';
2+
import { Button } from 'nhsuk-react-components';
23
import render from '@testing/render';
34
import { screen } from '@testing-library/react';
45

src/client/src/app/lib/components/nhsuk-frontend/button-group.tsx

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,31 @@
1-
import React from 'react';
2-
import { ReactNode, Children } from 'react';
1+
import React, { ReactNode, Children } from 'react';
32

43
type Props = {
54
children: ReactNode;
65
vertical?: boolean;
76
};
87

98
const ButtonGroup = ({ children, vertical = false }: Props) => {
10-
const childrenArray = Children.toArray(children);
11-
129
return (
1310
<ol
14-
className={`nhsuk-list nhsuk-u-clear nhsuk-u-margin-0 ${
11+
className={`nhsuk-list nhsuk-u-margin-0 nhsuk-button-group-flat ${
1512
vertical ? 'flex-col' : 'flex-row'
1613
}`}
1714
style={{
1815
display: 'flex',
1916
flexDirection: vertical ? 'column' : 'row',
20-
gap: '0.5rem',
17+
gap: '1rem',
2118
padding: 0,
2219
margin: 0,
2320
listStyle: 'none',
24-
alignItems: vertical ? '' : 'center',
21+
alignItems: vertical ? 'stretch' : 'center',
2522
}}
2623
>
27-
{childrenArray.map((child, index) => {
28-
return (
29-
<li
30-
key={`button-list-${index}`}
31-
className={`nhsuk-a-to-z-min-width ${
32-
vertical ? '' : 'nhsuk-u-float-left nhsuk-u-margin-right-3'
33-
}`}
34-
>
35-
{child}
36-
</li>
37-
);
38-
})}
24+
{Children.toArray(children).map((child, index) => (
25+
<li key={index} className="nhsuk-u-margin-0">
26+
{child}
27+
</li>
28+
))}
3929
</ol>
4030
);
4131
};

src/client/src/app/lib/components/nhsuk-frontend/button.test.tsx

Lines changed: 0 additions & 42 deletions
This file was deleted.

src/client/src/app/lib/components/nhsuk-frontend/button.tsx

Lines changed: 0 additions & 53 deletions
This file was deleted.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const CheckBoxOrAll = () => {
2+
return (
3+
<div style={{ marginBottom: 8, marginLeft: 12, display: 'block' }}>or</div>
4+
);
5+
};
6+
7+
export default CheckBoxOrAll;

0 commit comments

Comments
 (0)