Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions frontend/src/__tests__/utils/form-actions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
setTemplateToDeleted,
setTemplateToSubmitted,
requestTemplateProof,
createProofingRequest,
getLetterVariantsForTemplate,
getLetterVariantById,
uploadDocxTemplate,
Expand All @@ -25,7 +26,9 @@ import {
} from '@utils/form-actions';
import { getSessionServer } from '@utils/amplify-utils';
import type {
CreateProofingRequest,
LetterVariant,
ProofRequest,
TemplateDto,
TemplateStatus,
} from 'nhs-notify-web-template-management-types';
Expand Down Expand Up @@ -1354,4 +1357,83 @@ describe('form-actions', () => {
).rejects.toThrow('Failed to get access token');
});
});

describe('createProofingRequest', () => {
test('creates proofing request successfully', async () => {
const responseData: ProofRequest = {
id: 'proof-request-id',
contactDetailValue: 'test@example.com',
createdAt: '2026-05-20T10:00:00.000Z',
createdBy: 'user1',
templateId: 'template-id',
templateType: 'EMAIL',
testPatientNhsNumber: '1234567890',
personalisation: {
firstName: 'Jo',
},
};

mockedTemplateClient.createProofingRequest.mockResolvedValueOnce({
data: responseData,
});

const request: CreateProofingRequest = {
contactDetailId: 'contact-detail-id',
personalisation: {
firstName: 'Jo',
},
testPatientNhsNumber: '1234567890',
};

const response = await createProofingRequest('template-id', request);

expect(mockedTemplateClient.createProofingRequest).toHaveBeenCalledWith(
'template-id',
'token',
request
);

expect(response).toEqual(responseData);
});

test('should throw error when creation unexpectedly fails', async () => {
mockedTemplateClient.createProofingRequest.mockResolvedValueOnce({
error: {
errorMeta: {
code: 400,
description: 'Bad request',
},
},
});

const request: CreateProofingRequest = {
testPatientNhsNumber: '1234567890',
};

await expect(
createProofingRequest('template-id', request)
).rejects.toThrow('Failed to create a proofing request');

expect(mockedTemplateClient.createProofingRequest).toHaveBeenCalledWith(
'template-id',
'token',
request
);
});

test('should throw error when no token', async () => {
authIdTokenServerMock.mockResolvedValueOnce({
accessToken: undefined,
clientId: undefined,
});

const request: CreateProofingRequest = {
testPatientNhsNumber: '1234567890',
};

await expect(
createProofingRequest('template-id', request)
).rejects.toThrow('Failed to get access token');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export function SendTestMessage({
<div className='nhsuk-grid-row'>
<div className='nhsuk-grid-column-two-thirds'>
<NHSNotifyFormProvider serverAction={serverAction}>
<NHSNotifyForm.ErrorSummary />
<h1>{pageHeading}</h1>

<ContentRenderer
Expand All @@ -75,8 +76,6 @@ export function SendTestMessage({
<NHSNotifyForm.Form formId={formId}>
<input type='hidden' name='templateId' value={template.id} />

<NHSNotifyForm.ErrorSummary />

{children}

<TestPersonalisationForm
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,11 @@ describe('SendTestNhsAppMessage', () => {
'Enter a test patient NHS number that starts with 9',
'4010232137',
],
[
'less than 10 digits NHS number',
'The test patient NHS number must be 10 digits',
'943476591',
],
] as const)(
'should display error messages for %s',
(_caseName, errorMessage, testNhsNumber) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,38 @@ exports[`SendTestNhsAppMessage matches snapshot in validation error state 1`] =
<div
class="nhsuk-grid-column-two-thirds"
>
<div
aria-labelledby="error-summary-title"
class="nhsuk-error-summary"
role="alert"
tabindex="-1"
>
<h2
class="nhsuk-error-summary__title"
data-testid="error-summary"
id="error-summary-title"
>
There is a problem
</h2>
<ul
class="nhsuk-list nhsuk-error-summary__list"
>
<li>
<a
href="#testNhsNumber"
>
Enter a test patient NHS number in the correct format, like 9991234567 or 999 123 4567
</a>
</li>
<li>
<a
href="#custom-appointmentDate"
>
Enter a value for appointmentDate
</a>
</li>
</ul>
</div>
<h1>
Send a test NHS App message
</h1>
Expand Down Expand Up @@ -253,38 +285,6 @@ exports[`SendTestNhsAppMessage matches snapshot in validation error state 1`] =
type="hidden"
value="app-template-id"
/>
<div
aria-labelledby="error-summary-title"
class="nhsuk-error-summary"
role="alert"
tabindex="-1"
>
<h2
class="nhsuk-error-summary__title"
data-testid="error-summary"
id="error-summary-title"
>
There is a problem
</h2>
<ul
class="nhsuk-list nhsuk-error-summary__list"
>
<li>
<a
href="#testNhsNumber"
>
Enter a test patient NHS number in the correct format, like 9991234567 or 999 123 4567
</a>
</li>
<li>
<a
href="#custom-appointmentDate"
>
Enter a value for appointmentDate
</a>
</li>
</ul>
</div>
<div
class="nhsuk-form-group nhsuk-form-group--error"
data-testid="test-nhs-number-form-group"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
$SendTestNhsAppMessageSchema,
} from '../server-action';
import type { FormState } from '@utils/types';
import { createProofingRequest } from '@utils/form-actions';
import { randomUUID } from 'node:crypto';

const validTemplateId = randomUUID();
Expand All @@ -25,6 +26,11 @@ jest.mock('next/navigation', () => ({
},
}));

jest.mock('@utils/form-actions', () => ({
createProofingRequest: jest.fn(),
}));
const createProofingRequestMock = jest.mocked(createProofingRequest);

describe('$SendTestNhsAppMessageSchema', () => {
const baseData = {
testNhsNumber: '9434765919',
Expand Down Expand Up @@ -131,55 +137,99 @@ describe('sendTestNhsAppMessageAction', () => {
jest.clearAllMocks();
});

// TODO: CCM-8366 - Add test for request with custom fields when implemented
const proofRequestId = 'test-proofing-request-id';
const testNhsNumber = '9434765919';

test('redirects to confirmation screen on successful validation without custom fields', async () => {
const formData = getMockFormData({
testNhsNumber: '9434765919',
testNhsNumber: testNhsNumber,
templateId: validTemplateId,
});

createProofingRequestMock.mockResolvedValue({
id: proofRequestId,
contactDetailValue: 'test',
createdAt: 'test',
createdBy: 'test',
templateId: validTemplateId,
templateType: 'NHS_APP',
testPatientNhsNumber: testNhsNumber,
});

await sendTestNhsAppMessageAction(mockFormState, formData);

// TODO: CCM-8366 - Update to use proofing request ID instead of template ID
expect(redirect).toHaveBeenCalledWith(
`/test-nhs-app-message-sent/${validTemplateId}`,
`/test-nhs-app-message-sent/${proofRequestId}`,
'push'
);
expect(createProofingRequestMock).toHaveBeenCalledWith(validTemplateId, {
testPatientNhsNumber: testNhsNumber,
personalisation: {},
});
});

test('redirects to confirmation screen when multiple custom fields are populated', async () => {
const formData = getMockFormData({
testNhsNumber: '9434765919',
testNhsNumber: testNhsNumber,
templateId: validTemplateId,
'personalisation|appointmentDate': 'Monday 10th March',
'personalisation|clinicLocation': 'Clinic A',
'personalisation|nameOfSurgery': 'Surgery B',
});

createProofingRequestMock.mockResolvedValue({
id: proofRequestId,
contactDetailValue: 'test',
createdAt: 'test',
createdBy: 'test',
templateId: validTemplateId,
templateType: 'NHS_APP',
testPatientNhsNumber: testNhsNumber,
});

await sendTestNhsAppMessageAction(mockFormState, formData);

// TODO: CCM-8366 - Update to use proofing request ID instead of template ID
expect(redirect).toHaveBeenCalledWith(
`/test-nhs-app-message-sent/${validTemplateId}`,
`/test-nhs-app-message-sent/${proofRequestId}`,
'push'
);
expect(createProofingRequestMock).toHaveBeenCalledWith(validTemplateId, {
testPatientNhsNumber: testNhsNumber,
personalisation: {
appointmentDate: 'Monday 10th March',
clinicLocation: 'Clinic A',
nameOfSurgery: 'Surgery B',
},
});
});

test('redirects to confirmation screen when valid test NHS number contains spaces', async () => {
const nhsNumberWithSpaces = '943 476 5919';
const formData = getMockFormData({
testNhsNumber: '943 476 5919',
testNhsNumber: nhsNumberWithSpaces,
templateId: validTemplateId,
});

createProofingRequestMock.mockResolvedValue({
id: proofRequestId,
contactDetailValue: 'test',
createdAt: 'test',
createdBy: 'test',
templateId: validTemplateId,
templateType: 'NHS_APP',
testPatientNhsNumber: testNhsNumber,
});

await sendTestNhsAppMessageAction(mockFormState, formData);

// TODO: CCM-8366 - Add test for request with normalised NHS number
// TODO: CCM-8366 - Update to use proofing request ID instead of template ID
expect(redirect).toHaveBeenCalledWith(
`/test-nhs-app-message-sent/${validTemplateId}`,
`/test-nhs-app-message-sent/${proofRequestId}`,
'push'
);
expect(createProofingRequestMock).toHaveBeenCalledWith(validTemplateId, {
testPatientNhsNumber: '9434765919',
personalisation: {},
});
});

describe('error scenarios', () => {
Expand Down
Loading
Loading