Skip to content

CCM-8354: NHS App test message details#945

Open
nicki-nhs wants to merge 28 commits into
mainfrom
feature/CCM-8354-nhs-app-digital-proofing
Open

CCM-8354: NHS App test message details#945
nicki-nhs wants to merge 28 commits into
mainfrom
feature/CCM-8354-nhs-app-digital-proofing

Conversation

@nicki-nhs
Copy link
Copy Markdown
Contributor

@nicki-nhs nicki-nhs commented May 6, 2026

Description

  • Creates send-test-nhs-app-message page
  • Creates SendTestMessage component which will be used for the other digital channels
  • Creates TestPersonalisationForm and CustomFieldsForm components
  • Refactors letter authoring to use the above components
  • Adds util for NHS number validation
  • Updates MarkdownContent to merge overrides on links
  • Adds customPersonalisation to schema for digital templates
  • Extends functionality of template factory test helper
  • Updates template repository to save custom personalisation to the DB when creating/updating template
send-test-nhs-app-message-custom-fields-initial-load send-test-nhs-app-message-custom-fields-initial-errors

Context

Allows users to enter the details to request digital proofs of their NHS App templates

Type of changes

  • Refactoring (non-breaking change)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would change existing functionality)
  • Bug fix (non-breaking change which fixes an issue)

Checklist

  • I am familiar with the contributing guidelines
  • I have followed the code style of the project
  • I have added tests to cover my changes
  • I have updated the documentation accordingly
  • This PR is a result of pair or mob programming

Sensitive Information Declaration

To ensure the utmost confidentiality and protect your and others privacy, we kindly ask you to NOT including PII (Personal Identifiable Information) / PID (Personal Identifiable Data) or any other sensitive data in this PR (Pull Request) and the codebase changes. We will remove any PR that do contain any sensitive information. We really appreciate your cooperation in this matter.

  • I confirm that neither PII/PID nor sensitive data are included in this PR and the codebase changes.

@nicki-nhs nicki-nhs requested a review from a team as a code owner May 6, 2026 13:57
@nicki-nhs nicki-nhs changed the title CCM-8354 NHS App digital proofing CCM-8354: NHS App digital proofing May 6, 2026
@nicki-nhs nicki-nhs changed the title CCM-8354: NHS App digital proofing CCM-8354: NHS App test message details May 6, 2026
Comment thread infrastructure/terraform/modules/backend-api/spec.tmpl.json
@@ -0,0 +1,128 @@
import SendTestNhsAppMessagePage, {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

last time we discussed as a team i thought we'd decided that having two separate approaches to where to put tests in the file structure was confusing and not what we wanted to do, did something change?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the ticket to move them to be adjacent to the code is lined up in the backlog, and will be coming soon, so it made sense to me to do it like that for new files so we've got less to move.
but happy to move to the tests dir for now if you feel strongly - but it'll all get moved soon anyway :)

Copy link
Copy Markdown
Contributor

@chris-elliott-nhsd chris-elliott-nhsd May 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we're definitely doing the change to all the tests (i remain against it) then fine this makes sense

Comment thread frontend/src/app/send-test-nhs-app-message/[templateId]/page.tsx
Comment thread frontend/src/components/forms/SendTestMessage/server-action.ts Outdated
Comment thread frontend/src/components/forms/SendTestMessage/SendTestMessage.tsx Outdated
Comment thread frontend/src/components/molecules/MarkdownContent/MarkdownContent.tsx Outdated
Comment thread frontend/src/content/content.ts Outdated
Comment thread tests/test-team/helpers/capture-evidence.ts
expect(submitButton).toHaveAttribute('type', 'submit');
});

it('uses default serverAction passthrough when no serverAction is provided', async () => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why would this be a case we want to support?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test coverage complaint :D

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i mean why does serverAction need to be optional at all on SendTestMessage.tsx

).not.toBeInTheDocument();
});

it('should render children when provided', () => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't appear to ever be using children in for TestPersonlisationForm in the app code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interesting, I cant remember why I had this.... :D will check, maybe it was for a future ticket...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah I've remembered I think

I was originally planning on putting the "Personalisation" heading + description in as children (not in the version we want for letters)

but then ended up doing this instead in SendTestMessage

                <section data-testid='personalisation-form-section'>
                  <h2 className='nhsuk-heading-m nhsuk-u-margin-top-6'>
                    {content.personalisationSection.heading}
                  </h2>

                  <p className='nhsuk-body'>
                    {content.personalisationSection.description[templateType]}
                  </p>

                  <TestPersonalisationForm
                    templateType={templateType}
                    recipientField={recipientField}
                    customFields={customFields}
                  />
                </section>

but we could
move
<section data-testid='personalisation-form-section'> to the root of TestPersonalisationForm
and then
do this in SendTestMessage

                  <TestPersonalisationForm
                    templateType={templateType}
                    recipientField={recipientField}
                    customFields={customFields}
                  >
                    <h2 className='nhsuk-heading-m nhsuk-u-margin-top-6'>
                        {content.personalisationSection.heading}
                    </h2>

                    <p className='nhsuk-body'>
                        {content.personalisationSection.description[templateType]}
                    </p>
                </TestPersonalisationForm>

what do you think?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't mind either way, but i think children should either be used or removed as an option

classifyPersonalisation([
'firstName',
'clinicName',
'date',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick but 'date' is actually banned in digital channel personsalisation, so it might be confusing if it appears in test data in a couple of places

digitalProofingDisabledUser: TestUser
) {
return {
validNhsAppTemplate: {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add one to cover SUBMITTED status?

return this;
}

setCustomPersonalisation(custom: string[]) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For letters we also store systemPersonalisation (there is an existing update builder method called setPersonalisation, an empty array is set if there is no custom/system). We're not reading systemPersonalisation but I think it would be better to keep digital templates aligned if possible

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had that at first but @chris-elliott-nhsd thought we should just add a separate method to just use custom since that's what all we need for digital - you guys can argue amongst yourselves about it cos I dont feel strongly either way :D

);

export type EmailProperties = {
customPersonalisation?: Array<string>;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These aren't type specific, they belong on BaseCreatedTemplate

Copy link
Copy Markdown
Contributor

@alexnuttall alexnuttall May 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I'm forgetting about PDF letters, which don't have it - but still might be better to just have it optional on all templates


export const $EmailProperties = schemaFor<EmailProperties>()(
z.object({
customPersonalisation: z.array(z.string()).optional(),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these could go in $BaseTemplateDto

.setUpdatedByUserAt(this.internalUserKey(user))
.incrementLockNumber();

if (customPersonalisation?.length > 0) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we set empty array for letters if there is no custom personalisation, so I think this should match

mode = 'block',
overrides,
}: MarkdownContentProps) {
const isPlainObject = (value: unknown): value is Record<string, unknown> =>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't need to be defined inside a component, it's more efficient in module scope

return [...new Set(parameters)];
}

export function classifyPersonalisation(parameters: string[]): {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Personalisation type in letter-preview-renderer could move to utils/src/types

};
}

const { templateId, testNhsNumber } = result.data;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we make this testPatientNhsNumber to match the event schema?


const personalisation = {
...customPersonalisation,
nhsNumber: testNhsNumber,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NHS number shouldn't go in personalisation, we get it from PDS in core - since in rare cases it can be changed

Requests where personalisation contains nhsNumber will be rejected: https://github.com/NHSDigital/comms-mgr/blob/120f59bef4bb6d4e1c9df81fbae84b35f0badd27/packages/libs/utils/src/constants.ts#L20

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants