Skip to content

Commit

Permalink
Overwrite existing bed fields with user input
Browse files Browse the repository at this point in the history
Before this change if the API threw an error when the page was loaded
the inputs of the form would be populated with the data from the OoS bed
not the erroneously inputted data. We want to show the erroneous data so
the user can see where they've gone wrong and correct their mistake.
I'm not happy with the amount of casting I've had to do here but time
doesn't allow for type assertions currently.
  • Loading branch information
rich committed Jul 11, 2024
1 parent e74583f commit 300b5cd
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
} from '../../utils/validation'
import { SanitisedError } from '../../sanitisedError'
import { ErrorsAndUserInput } from '../../@types/ui'
import * as OoSBedUtils from '../../utils/outOfServiceBedUtils'

jest.mock('../../utils/validation')

Expand Down Expand Up @@ -124,6 +125,55 @@ describe('updateOutOfServiceBedController', () => {
}),
)
})

it('renders the form with errors and user input if theres an error', async () => {
const errorsAndUserInput = createMock<ErrorsAndUserInput>()
when(fetchErrorsAndUserInput).calledWith(request).mockReturnValue(errorsAndUserInput)

const requestHandler = updateOutOfServiceBedController.new()

await requestHandler(request, response, next)

expect(response.render).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({
errors: errorsAndUserInput.errors,
errorSummary: errorsAndUserInput.errorSummary,
...errorsAndUserInput.userInput,
}),
)
})

describe('if there is an error for a field', () => {
it('overwrites the pre-existing OoS bed record when there is more recent user input ', async () => {
const errorsAndUserInput = createMock<ErrorsAndUserInput>({
userInput: {
startDate: '2025-06-01',
endDate: '2025-06-01',
referenceNumber: 'new reference number',
},
})
when(fetchErrorsAndUserInput).calledWith(request).mockReturnValue(errorsAndUserInput)

const spy = jest
.spyOn(OoSBedUtils, 'overwriteOoSBedWithUserInput')
.mockReturnValue({ ...outOfServiceBed, ...errorsAndUserInput.userInput })

const requestHandler = updateOutOfServiceBedController.new()

await requestHandler(request, response, next)

expect(spy).toHaveBeenCalledWith(errorsAndUserInput.userInput, outOfServiceBed)
expect(response.render).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({
startDate: errorsAndUserInput.userInput.startDate,
endDate: errorsAndUserInput.userInput.endDate,
referenceNumber: errorsAndUserInput.userInput.referenceNumber,
}),
)
})
})
})

describe('create', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from '../../utils/validation'
import paths from '../../paths/manage'
import { SanitisedError } from '../../sanitisedError'
import { overwriteOoSBedWithUserInput } from '../../utils/outOfServiceBedUtils'

export default class OutOfServiceBedsController {
constructor(
Expand All @@ -24,19 +25,21 @@ export default class OutOfServiceBedsController {
const outOfServiceBedReasons = await this.outOfServiceBedService.getOutOfServiceBedReasons(req.user.token)
const outOfServiceBed = await this.outOfServiceBedService.getOutOfServiceBed(req.user.token, premisesId, id)

const outOfServiceBedWithUserInput = overwriteOoSBedWithUserInput(userInput, outOfServiceBed)

res.render('v2Manage/outOfServiceBeds/update', {
pageHeading: 'updateOutOfServiceBedsController',
premisesId,
bedId,
id,
outOfServiceBedReasons,
outOfServiceBed,
...DateFormats.isoDateToDateInputs(outOfServiceBed.startDate, 'startDate'),
...DateFormats.isoDateToDateInputs(outOfServiceBed.endDate, 'endDate'),
...DateFormats.isoDateToDateInputs(outOfServiceBedWithUserInput.startDate, 'startDate'),
...DateFormats.isoDateToDateInputs(outOfServiceBedWithUserInput.endDate, 'endDate'),
errors,
errorSummary,
errorTitle,
...userInput,
outOfServiceBed: outOfServiceBedWithUserInput,
})
}
}
Expand Down
33 changes: 33 additions & 0 deletions server/utils/outOfServiceBedUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
outOfServiceBedCountForToday,
outOfServiceBedTableHeaders,
outOfServiceBedTableRows,
overwriteOoSBedWithUserInput,
referenceNumberCell,
sortOutOfServiceBedRevisionsByUpdatedAt,
} from './outOfServiceBedUtils'
Expand Down Expand Up @@ -263,4 +264,36 @@ describe('outOfServiceBedUtils', () => {
expect(sortedRevisions).toEqual([latestDate, middleDate, earliestDate])
})
})

describe('overwriteOoSBedWithUserInput', () => {
it.each(['startDate', 'endDate'])('overwrites %s with user input', key => {
const userInput = { [key]: 'new value' }
const outOfServiceBed = outOfServiceBedFactory.build()

expect(overwriteOoSBedWithUserInput(userInput, outOfServiceBed)).toEqual({
...outOfServiceBed,
[key]: 'new value',
})
})

it('overwrites the reason ID if there is a reason in the userInput', () => {
const userInput = { outOfServiceBed: { reason: 'new reason' } }
const outOfServiceBed = outOfServiceBedFactory.build()

expect(overwriteOoSBedWithUserInput(userInput, outOfServiceBed)).toEqual(
expect.objectContaining({
reason: expect.objectContaining({ id: 'new reason' }),
}),
)
})

it('overwrites the reference number if there is a reason in the userInput', () => {
const userInput = { outOfServiceBed: { referenceNumber: 'new reason' } }
const outOfServiceBed = outOfServiceBedFactory.build()

expect(overwriteOoSBedWithUserInput(userInput, outOfServiceBed)).toEqual(
expect.objectContaining({ referenceNumber: 'new reason' }),
)
})
})
})
21 changes: 21 additions & 0 deletions server/utils/outOfServiceBedUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,24 @@ export const sortOutOfServiceBedRevisionsByUpdatedAt = (revisions: Array<Cas1Out
return a.updatedAt > b.updatedAt ? -1 : 1
})
}

export const overwriteOoSBedWithUserInput = (userInput: Record<string, unknown>, outOfServiceBed: OutOfServiceBed) => {
;['startDate', 'endDate'].forEach(key => {
if (userInput[key]) {
outOfServiceBed[key] = userInput[key]
}
})

if (userInput.outOfServiceBed && (userInput.outOfServiceBed as Record<string, string>)?.referenceNumber) {
outOfServiceBed.referenceNumber = (userInput.outOfServiceBed as Record<string, string>)?.referenceNumber
}

if (
(userInput?.outOfServiceBed as Record<string, string>)?.reason &&
typeof (userInput.outOfServiceBed as Record<string, string>)?.reason === 'string'
) {
outOfServiceBed.reason.id = (userInput.outOfServiceBed as Record<string, string>).reason
}

return outOfServiceBed
}

0 comments on commit 300b5cd

Please sign in to comment.