Skip to content

Commit af43504

Browse files
committed
CCM-10893 Update header and add unit tests
1 parent a5c0389 commit af43504

File tree

3 files changed

+526
-84
lines changed

3 files changed

+526
-84
lines changed
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
import React from 'react';
2+
import {
3+
render,
4+
screen,
5+
waitFor,
6+
within,
7+
} from '@testing-library/react';
8+
import { mockDeep } from 'jest-mock-extended';
9+
import NhsNotifyHeaderWithAccount from '@molecules/HeaderWithAccount/HeaderWithAccount';
10+
import { type UseAuthenticator, useAuthenticator } from '@aws-amplify/ui-react';
11+
12+
jest.mock('@aws-amplify/ui-react');
13+
14+
const mockFetchAuthSession = jest.fn();
15+
jest.mock('aws-amplify/auth', () => ({
16+
fetchAuthSession: (...args: any[]) => mockFetchAuthSession(...args),
17+
}));
18+
19+
const mockGetIdTokenClaims = jest.fn();
20+
jest.mock('@utils/token-utils', () => ({
21+
getIdTokenClaims: (...args: any[]) => mockGetIdTokenClaims(...args),
22+
}));
23+
24+
const setAuthStatus = (
25+
status: 'authenticated' | 'unauthenticated' | 'configuring'
26+
) => {
27+
jest.mocked(useAuthenticator).mockImplementation((selector) => {
28+
const context = mockDeep<UseAuthenticator>({
29+
authStatus: status,
30+
});
31+
32+
if (selector) {
33+
selector(context);
34+
}
35+
36+
return context;
37+
});
38+
};
39+
40+
describe('NhsNotifyHeaderWithAccount', () => {
41+
describe('when unauthenticated', () => {
42+
beforeEach(() => {
43+
jest.resetAllMocks();
44+
setAuthStatus('unauthenticated');
45+
});
46+
47+
it('renders the logo and service name with the correct url', () => {
48+
render(<NhsNotifyHeaderWithAccount />);
49+
50+
const logoServiceLink = screen.getByTestId('header-logo-service-link');
51+
52+
expect(logoServiceLink).toContainElement(
53+
screen.getByRole('img', { name: 'NHS logo' })
54+
);
55+
expect(logoServiceLink).toHaveAttribute('href', '/message-templates');
56+
expect(logoServiceLink).toHaveTextContent('Notify');
57+
});
58+
59+
it(`renders the authentication link as 'sign in'`, () => {
60+
render(<NhsNotifyHeaderWithAccount />);
61+
62+
expect(screen.getByTestId('auth-link')).toHaveTextContent('Sign in');
63+
});
64+
65+
it('does not fetch session or claims', async () => {
66+
render(<NhsNotifyHeaderWithAccount />);
67+
68+
await Promise.resolve();
69+
70+
expect(mockFetchAuthSession).not.toHaveBeenCalled();
71+
expect(mockGetIdTokenClaims).not.toHaveBeenCalled();
72+
});
73+
74+
it('matches snapshot (unauthenticated)', () => {
75+
const container = render(<NhsNotifyHeaderWithAccount />);
76+
77+
expect(container.asFragment()).toMatchSnapshot();
78+
});
79+
});
80+
81+
describe('when authenticated', () => {
82+
beforeEach(() => {
83+
jest.resetAllMocks();
84+
setAuthStatus('authenticated');
85+
86+
mockFetchAuthSession.mockResolvedValue({
87+
tokens: {
88+
idToken: { toString: () => 'fake.id.token' },
89+
accessToken: { toString: () => 'fake.access.token' },
90+
},
91+
});
92+
93+
mockGetIdTokenClaims.mockReturnValue({
94+
displayName: 'Dr Test Example',
95+
clientName: 'NHS England',
96+
});
97+
});
98+
99+
it('renders the users display name', async () => {
100+
render(<NhsNotifyHeaderWithAccount />);
101+
102+
await waitFor(() => {
103+
expect(screen.getByTestId('account-display-name')).toHaveTextContent(
104+
'Dr Test Example'
105+
);
106+
});
107+
});
108+
109+
it('renders the client name', async () => {
110+
render(<NhsNotifyHeaderWithAccount />);
111+
112+
await waitFor(() => {
113+
expect(screen.getByTestId('account-client-name')).toHaveTextContent(
114+
'NHS England'
115+
);
116+
});
117+
});
118+
119+
it(`renders auth link as 'Sign out'`, async () => {
120+
render(<NhsNotifyHeaderWithAccount />);
121+
122+
await waitFor(() => {
123+
expect(screen.getByTestId('auth-link')).toHaveTextContent('Sign out');
124+
});
125+
});
126+
127+
it('handles missing id token by clearing names', async () => {
128+
mockFetchAuthSession.mockResolvedValueOnce({
129+
tokens: {
130+
idToken: undefined,
131+
accessToken: { toString: () => 'fake.access.token' },
132+
},
133+
});
134+
135+
render(<NhsNotifyHeaderWithAccount />);
136+
137+
await waitFor(() => {
138+
expect(screen.queryByTestId('account-display-name')).toBeNull();
139+
expect(screen.queryByTestId('account-client-name')).toBeNull();
140+
});
141+
});
142+
143+
it('handles fetchAuthSession errors by clearing names', async () => {
144+
mockFetchAuthSession.mockRejectedValueOnce(new Error('boom'));
145+
146+
render(<NhsNotifyHeaderWithAccount />);
147+
148+
await waitFor(() => {
149+
expect(screen.queryByTestId('account-display-name')).toBeNull();
150+
expect(screen.queryByTestId('account-client-name')).toBeNull();
151+
});
152+
});
153+
154+
it('matches snapshot (authenticated)', () => {
155+
const container = render(<NhsNotifyHeaderWithAccount />);
156+
157+
expect(container.asFragment()).toMatchSnapshot();
158+
});
159+
});
160+
161+
describe(`with 'routing' flag enabled`, () => {
162+
it('renders both the navigation links with correct hrefs', () => {
163+
render(<NhsNotifyHeaderWithAccount features={{ routing: true }} />);
164+
165+
const nav = screen.getByTestId('navigation-links');
166+
167+
const templatesLink = within(nav).getByRole('link', {
168+
name: 'Templates',
169+
});
170+
expect(templatesLink).toHaveAttribute('href', '/message-templates');
171+
172+
const plansLink = within(nav).getByRole('link', {
173+
name: 'Message plans',
174+
});
175+
expect(plansLink).toHaveAttribute(
176+
'href',
177+
'/templates-and-message-plans/message-plans'
178+
);
179+
});
180+
});
181+
182+
describe(`with 'routing' flag disabled`, () => {
183+
it('renders the templates link with correct href', () => {
184+
render(<NhsNotifyHeaderWithAccount features={{ routing: false }} />);
185+
186+
const nav = screen.getByTestId('navigation-links');
187+
188+
const templatesLink = within(nav).getByRole('link', {
189+
name: 'Templates',
190+
});
191+
expect(templatesLink).toHaveAttribute('href', '/message-templates');
192+
});
193+
194+
it('should not render the message plans link', () => {
195+
render(<NhsNotifyHeaderWithAccount features={{ routing: false }} />);
196+
197+
const nav = screen.getByTestId('navigation-links');
198+
199+
const plansLink = within(nav).queryByRole('link', {
200+
name: 'Message plans',
201+
});
202+
expect(plansLink).not.toBeInTheDocument();
203+
});
204+
});
205+
});
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`NhsNotifyHeaderWithAccount when authenticated matches snapshot (authenticated) 1`] = `
4+
<DocumentFragment>
5+
<header
6+
class="nhsuk-header"
7+
data-module="nhsuk-header"
8+
data-testid="page-header"
9+
role="banner"
10+
>
11+
<div
12+
class="nhsuk-header__container nhsuk-width-container"
13+
>
14+
<div
15+
class="nhsuk-header__service"
16+
>
17+
<a
18+
aria-label="NHS Notify templates"
19+
class="nhsuk-header__service-logo"
20+
data-testid="header-logo-service-link"
21+
href="/message-templates"
22+
>
23+
<svg
24+
class="nhsuk-header__logo"
25+
focusable="false"
26+
height="40"
27+
role="img"
28+
viewBox="0 0 200 80"
29+
width="100"
30+
xmlns="http://www.w3.org/2000/svg"
31+
>
32+
<title>
33+
NHS logo
34+
</title>
35+
<path
36+
d="M200 0v80H0V0h200Zm-27.5 5.5c-14.5 0-29 5-29 22 0 10.2 7.7 13.5 14.7 16.3l.7.3c5.4 2 10.1 3.9 10.1 8.4 0 6.5-8.5 7.5-14 7.5s-12.5-1.5-16-3.5L135 70c5.5 2 13.5 3.5 20 3.5 15.5 0 32-4.5 32-22.5 0-19.5-25.5-16.5-25.5-25.5 0-5.5 5.5-6.5 12.5-6.5a35 35 0 0 1 14.5 3l4-13.5c-4.5-2-12-3-20-3Zm-131 2h-22l-14 65H22l9-45h.5l13.5 45h21.5l14-65H64l-9 45h-.5l-13-45Zm63 0h-18l-13 65h17l6-28H117l-5.5 28H129l13.5-65H125L119.5 32h-20l5-24.5Z"
37+
fill="currentcolor"
38+
/>
39+
</svg>
40+
<span
41+
class="nhsuk-header__service-name"
42+
>
43+
Notify
44+
</span>
45+
</a>
46+
</div>
47+
<nav
48+
aria-label="Account"
49+
class="nhsuk-header__account"
50+
>
51+
<ul
52+
class="nhsuk-header__account-list"
53+
>
54+
<li
55+
class="nhsuk-header__account-item"
56+
>
57+
<a
58+
class="auth-link nhsuk-header__account-link"
59+
data-testid="auth-link"
60+
href="/auth/signout"
61+
id="sign-out-link"
62+
>
63+
Sign out
64+
</a>
65+
</li>
66+
</ul>
67+
</nav>
68+
</div>
69+
<nav
70+
aria-label="Menu"
71+
class="nhsuk-header__navigation"
72+
data-testid="navigation-links"
73+
>
74+
<div
75+
class="nhsuk-header__navigation-container nhsuk-width-container"
76+
>
77+
<ul
78+
class="nhsuk-header__navigation-list"
79+
>
80+
<li
81+
class="nhsuk-header__navigation-item"
82+
>
83+
<a
84+
class="nhsuk-header__navigation-link"
85+
href="/message-templates"
86+
>
87+
Templates
88+
</a>
89+
</li>
90+
</ul>
91+
</div>
92+
</nav>
93+
</header>
94+
</DocumentFragment>
95+
`;
96+
97+
exports[`NhsNotifyHeaderWithAccount when unauthenticated matches snapshot (unauthenticated) 1`] = `
98+
<DocumentFragment>
99+
<header
100+
class="nhsuk-header"
101+
data-module="nhsuk-header"
102+
data-testid="page-header"
103+
role="banner"
104+
>
105+
<div
106+
class="nhsuk-header__container nhsuk-width-container"
107+
>
108+
<div
109+
class="nhsuk-header__service"
110+
>
111+
<a
112+
aria-label="NHS Notify templates"
113+
class="nhsuk-header__service-logo"
114+
data-testid="header-logo-service-link"
115+
href="/message-templates"
116+
>
117+
<svg
118+
class="nhsuk-header__logo"
119+
focusable="false"
120+
height="40"
121+
role="img"
122+
viewBox="0 0 200 80"
123+
width="100"
124+
xmlns="http://www.w3.org/2000/svg"
125+
>
126+
<title>
127+
NHS logo
128+
</title>
129+
<path
130+
d="M200 0v80H0V0h200Zm-27.5 5.5c-14.5 0-29 5-29 22 0 10.2 7.7 13.5 14.7 16.3l.7.3c5.4 2 10.1 3.9 10.1 8.4 0 6.5-8.5 7.5-14 7.5s-12.5-1.5-16-3.5L135 70c5.5 2 13.5 3.5 20 3.5 15.5 0 32-4.5 32-22.5 0-19.5-25.5-16.5-25.5-25.5 0-5.5 5.5-6.5 12.5-6.5a35 35 0 0 1 14.5 3l4-13.5c-4.5-2-12-3-20-3Zm-131 2h-22l-14 65H22l9-45h.5l13.5 45h21.5l14-65H64l-9 45h-.5l-13-45Zm63 0h-18l-13 65h17l6-28H117l-5.5 28H129l13.5-65H125L119.5 32h-20l5-24.5Z"
131+
fill="currentcolor"
132+
/>
133+
</svg>
134+
<span
135+
class="nhsuk-header__service-name"
136+
>
137+
Notify
138+
</span>
139+
</a>
140+
</div>
141+
<nav
142+
aria-label="Account"
143+
class="nhsuk-header__account"
144+
>
145+
<ul
146+
class="nhsuk-header__account-list"
147+
>
148+
<li
149+
class="nhsuk-header__account-item"
150+
>
151+
<a
152+
class="auth-link nhsuk-header__account-link"
153+
data-testid="auth-link"
154+
href="/auth?redirect=%2Ftemplates%2Fcreate-and-submit-templates"
155+
id="sign-in-link"
156+
>
157+
Sign in
158+
</a>
159+
</li>
160+
</ul>
161+
</nav>
162+
</div>
163+
<nav
164+
aria-label="Menu"
165+
class="nhsuk-header__navigation"
166+
data-testid="navigation-links"
167+
>
168+
<div
169+
class="nhsuk-header__navigation-container nhsuk-width-container"
170+
>
171+
<ul
172+
class="nhsuk-header__navigation-list"
173+
>
174+
<li
175+
class="nhsuk-header__navigation-item"
176+
>
177+
<a
178+
class="nhsuk-header__navigation-link"
179+
href="/message-templates"
180+
>
181+
Templates
182+
</a>
183+
</li>
184+
</ul>
185+
</div>
186+
</nav>
187+
</header>
188+
</DocumentFragment>
189+
`;

0 commit comments

Comments
 (0)