Skip to content

CCM-15042: letter render error handling#901

Open
ClareJonesBJSS wants to merge 4 commits intomainfrom
feature/CCM-15042_letter-gen-errors
Open

CCM-15042: letter render error handling#901
ClareJonesBJSS wants to merge 4 commits intomainfrom
feature/CCM-15042_letter-gen-errors

Conversation

@ClareJonesBJSS
Copy link
Copy Markdown
Contributor

@ClareJonesBJSS ClareJonesBJSS commented Apr 8, 2026

Description

  • Adds render check to 'Approve template'
  • Adds empty personalisations check to 'Update preview'
  • Adds new context for the errors so all error summaries can appear at the top whilst remaining separate forms
  • Tweaked the letter render tabs so they don't use unneeded form providers when we're in a read-only context
  • Amended Select, Input and FileInput atoms to correctly apply error styling, and to do so based on field id rather than name - we have to use id so that our use of htmlFor is correct, and the links in the summary go to the right place - Also switched a couple of places that weren't using those atoms to use them, resulting in a few fields changing outside of the scope of the ticket, along with some other snapshots updating now the styling is correct, but it felt like too small a bug to bother ticketing separately.

Screenshot_8-4-2026_16289_localhost

Screenshot_10-4-2026_94252_localhost

Context

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.

@ClareJonesBJSS ClareJonesBJSS requested a review from a team as a code owner April 8, 2026 15:24
@ClareJonesBJSS ClareJonesBJSS force-pushed the feature/CCM-15042_letter-gen-errors branch 4 times, most recently from ab401d0 to f935271 Compare April 9, 2026 16:01
Comment thread frontend/src/app/preview-approved-letter-template/[templateId]/page.tsx Outdated
const { setParentErrorState, parentErrorState, letterRenderErrorState } =
useLetterRenderError();

useEffect(() => {
Copy link
Copy Markdown
Contributor

@chris-elliott-nhsd chris-elliott-nhsd Apr 10, 2026

Choose a reason for hiding this comment

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

why does this need to be in a useEffect? also seen elsewhere

Copy link
Copy Markdown
Contributor Author

@ClareJonesBJSS ClareJonesBJSS Apr 10, 2026

Choose a reason for hiding this comment

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

React will throw complaining that we're updating one component whilst rendering another if called directly, because we're bridging between NHSNotifyFormProvider and LetterRenderErrorProvider.

I could potentially get rid of some useEffects by making it more of a one-way thing from the letter render component and handling it in the page, but clearing one form's errors when the other triggers was tricky, and I found it much easier to pick through what was going on when I broke it out into the separate provider, plus it feels more easily reusable if we end up genning renders anywhere else

@ClareJonesBJSS ClareJonesBJSS changed the title CCM-15042: letter render error handling Draft: CCM-15042: letter render error handling Apr 10, 2026
@ClareJonesBJSS ClareJonesBJSS changed the title Draft: CCM-15042: letter render error handling CCM-15042: letter render error handling Apr 10, 2026
Comment thread frontend/src/content/content.ts Outdated
customSection: {
heading: 'Custom personalisation fields',
error: {
required: `Enter example data for {{field}}`,
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.

Suggested change
required: `Enter example data for {{field}}`,
required: 'Enter example data for {{field}}',

...props
}: Omit<HTMLProps<HTMLInputElement>, 'type'>) {
}: Omit<HTMLProps<HTMLInputElement>, 'type'> & { id: string; name: string }) {
const [state] = useNHSNotifyForm();
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.

Just wondering if it would be worth moving this or wrapping this in the NHSNotifyForm directory. We have a few "connected" components in there and exposed like NHSNotifyForm.Input, NHSNotifyForm.RadioInput etc. Since this now has to be rendered inside an NHSNotifyForm provider, then it might be better to move it into that mini module.

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.

Updated, and got rid of the full div, since it was only used in the pdf upload so is going away anyway

Comment thread frontend/src/components/atoms/FileUpload/FileUpload.tsx Outdated
@ClareJonesBJSS ClareJonesBJSS force-pushed the feature/CCM-15042_letter-gen-errors branch 2 times, most recently from 0a016e6 to 549b0f1 Compare April 15, 2026 13:01
harrim91
harrim91 previously approved these changes Apr 15, 2026
Comment on lines +38 to +39
this.errorSummary = page.locator('[class="nhsuk-error-summary"]');
this.errorSummaryLinks = this.errorSummary.locator('a');
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 feel like errorSummary exists on the base page so probs dont need this one?
and might be good idea to add the links locator there too, what do you think?

getInlineError: (fieldId: string): Locator =>
panel
.locator(`[id="${fieldId}"]`)
.locator('xpath=..')
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.

what you doing with this?

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.

it steps up to the parent div in order to find the correct sibling .nhsuk-error-message. Though now you ask it, I can't recall why I ended up doing it this way rather than just giving the error messages IDs 🤷‍♀️ will give the latter a try in the morning

@ClareJonesBJSS ClareJonesBJSS force-pushed the feature/CCM-15042_letter-gen-errors branch 2 times, most recently from 1d94c65 to b64137a Compare April 21, 2026 10:35
await expect(shortErrorLink).toBeHidden();
});

test('shows both short and long example errors when personalised renders have failed', 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.

I'm confused about this one - if the render has failed, will "Enter short example data" fix it?

Copy link
Copy Markdown
Contributor Author

@ClareJonesBJSS ClareJonesBJSS Apr 22, 2026

Choose a reason for hiding this comment

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

It has when I've done this scenario manually, but that's because there was nothing wrong with the ability to render and I'd manually edited in ddb to recreate it. No idea what could cause a genuine failure here so hard to say what we should be advising - if it were a transient carbone glitch or aws issue then rerender would be appropriate, but I suppose either way the message isn't accurate.

Copy link
Copy Markdown
Contributor Author

@ClareJonesBJSS ClareJonesBJSS Apr 22, 2026

Choose a reason for hiding this comment

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

Chatted with Lee about it, I'm thinking any scenario where a render is FAILED, either it will be resolved by a rerender, or we're in servicenow territory anyway (some system issue or eg the original docx has vanished from s3). Either way its not normal operations, so it's probably not worth giving it special handling, as long as we're pointing them at trying the render again (which will presumably be displaying 'No preview available' so it'll be obvious there's a problem), and blocking them from approving the template?

test('activates the hidden tab and focuses the field when its error link is clicked', async () => {
renderTabsWithError('hidden-tab-field');

const rafSpy = jest
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.

My main thought here is "is there a way to test this without all of this mocking?"

So e.g.

const field = document.querySelector('#hidden-tab-field');
expect(field).toHaveFocus()
const field = document.querySelector('#hidden-tab-field');
expect(focusMock).toHaveBeenCalledTimes(1);
expect(focusMock.mock.instances[0]).toBe(field);

userEvent tends to be a better option than fireEvent, I don't know if that'd help?

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.

Or can it be covered in playwright on the relevant pages?

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 think this is an improvement? 😵 and added a playwright test


/**
* Handles clicks on error summary links that point to form fields inside unselected NHS UK tab panels.
* Iff the target field is inside a hidden tab panel (`nhsuk-tabs__panel--hidden`), the default
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.

Suggested change
* Iff the target field is inside a hidden tab panel (`nhsuk-tabs__panel--hidden`), the default
* If the target field is inside a hidden tab panel (`nhsuk-tabs__panel--hidden`), the default

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.

Was actually intentional (if and only if), but fair 😅

Comment thread frontend/src/components/molecules/NhsNotifyErrorSummary/NhsNotifyErrorSummary.tsx Outdated
@ClareJonesBJSS ClareJonesBJSS force-pushed the feature/CCM-15042_letter-gen-errors branch from e215de9 to b49897e Compare April 22, 2026 16:24
Comment thread frontend/src/components/molecules/NhsNotifyErrorSummary/NhsNotifyErrorSummary.tsx Outdated
Comment thread frontend/src/components/molecules/NhsNotifyErrorSummary/NhsNotifyErrorSummary.tsx Outdated
andykay-nhs
andykay-nhs previously approved these changes Apr 24, 2026
);

expect(container.asFragment()).toMatchSnapshot();
expect(focusMock).toHaveBeenCalled();
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.

are we still testing this somewhere else?

'Choose example recipient'
);

const summaryLink = previewPage.errorSummaryLinks.filter({
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.

are we clicking these links anywhere?

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.

5 participants