Skip to content
Merged
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
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
},
"license": "SEE LICENSE IN LICENSE",
"dependencies": {
"@defra/forms-model": "^3.0.575",
"@defra/forms-model": "^3.0.579",
"@defra/hapi-tracing": "^1.26.0",
"@elastic/ecs-pino-format": "^1.5.0",
"@hapi/boom": "^10.0.1",
Expand Down
49 changes: 40 additions & 9 deletions src/server/plugins/engine/components/DeclarationField.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ describe('DeclarationField', () => {
const answer2 = getAnswer(field, state2)

expect(answer1).toBe('I understand and agree')
expect(answer2).toBe('')
expect(answer2).toBe('Not provided')
})

it('returns payload from state', () => {
Expand All @@ -197,7 +197,7 @@ describe('DeclarationField', () => {
const payload2 = field.getFormDataFromState(state2)

expect(payload1).toEqual(getFormData('true'))
expect(payload2).toEqual(getFormData())
expect(payload2).toEqual(getFormData('unchecked'))
})

it('returns value from state', () => {
Expand All @@ -208,7 +208,7 @@ describe('DeclarationField', () => {
const value2 = field.getFormValueFromState(state2)

expect(value1).toBe('true')
expect(value2).toBeUndefined()
expect(value2).toBe('unchecked')
})

it('returns context for conditions and form submission', () => {
Expand Down Expand Up @@ -246,7 +246,6 @@ describe('DeclarationField', () => {
label: { text: def.title },
name: 'myComponent',
attributes: {},
values: [],
content: 'Lorem ipsum dolar sit amet',
id: 'myComponent',
fieldset: {
Expand All @@ -257,7 +256,8 @@ describe('DeclarationField', () => {
items: [
{
value: 'true',
text: 'I understand and agree'
text: 'I understand and agree',
checked: true
}
]
})
Expand All @@ -276,10 +276,16 @@ describe('DeclarationField', () => {

expect(viewModel).toEqual(
expect.objectContaining({
values: ['true'],
hint: {
text: 'Please read and confirm the following'
}
},
items: [
{
value: 'true',
text: 'I understand and agree',
checked: true
}
]
})
)
})
Expand All @@ -301,14 +307,39 @@ describe('DeclarationField', () => {
collection = new ComponentCollection([def], { model })
field = collection.fields[0]

const viewModel = field.getViewModel(getFormData(['unchecked', 'true']))
const viewModel = field.getViewModel(getFormData(['true']))

expect(viewModel).toEqual(
expect.objectContaining({
items: [
{
value: 'true',
text: 'I consent to the processing of my personal data',
checked: true
}
]
})
)
})

it('sets checkbox as unchecked', () => {
def = {
...def,
hint: 'Please read and confirm the following'
} satisfies DeclarationFieldComponent

collection = new ComponentCollection([def], { model })
field = collection.fields[0]

const viewModel = field.getViewModel(getFormData(undefined))

expect(viewModel).toEqual(
expect.objectContaining({
items: [
{
value: 'true',
text: 'I consent to the processing of my personal data'
text: 'I understand and agree',
checked: false
}
]
})
Expand Down
11 changes: 6 additions & 5 deletions src/server/plugins/engine/components/DeclarationField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@ export class DeclarationField extends FormComponent {

getFormValueFromState(state: FormSubmissionState) {
const { name } = this
return state[name] === true ? 'true' : undefined
return state[name] === true ? 'true' : 'unchecked'
}

getFormDataFromState(state: FormSubmissionState): FormPayload {
const { name } = this
return { [name]: state[name] === true ? 'true' : undefined }
return { [name]: state[name] === true ? 'true' : 'unchecked' }
}

getStateFromValidForm(payload: FormPayload): FormState {
Expand All @@ -98,7 +98,7 @@ export class DeclarationField extends FormComponent {
}

getDisplayStringFromFormValue(value: FormValue | FormPayload): string {
return value ? this.declarationConfirmationLabel : ''
return value === 'true' ? this.declarationConfirmationLabel : 'Not provided'
}

getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {
Expand All @@ -110,6 +110,7 @@ export class DeclarationField extends FormComponent {
content,
declarationConfirmationLabel = defaultDeclarationConfirmationLabel
} = this
const isChecked = !!payload[this.name]
return {
...super.getViewModel(payload, errors),
hint: hint ? { text: hint } : undefined,
Expand All @@ -119,11 +120,11 @@ export class DeclarationField extends FormComponent {
}
},
content,
values: payload[this.name],
items: [
{
text: declarationConfirmationLabel,
value: 'true'
value: 'true',
checked: isChecked
}
]
}
Expand Down
85 changes: 85 additions & 0 deletions src/server/plugins/engine/components/helpers/components.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
ComponentType,
type DeclarationFieldComponent,
type EastingNorthingFieldComponent,
type LatLongFieldComponent,
type NationalGridFieldNumberFieldComponent,
Expand All @@ -11,6 +12,7 @@ import {
getAnswerMarkdown
} from '~/src/server/plugins/engine/components/helpers/components.js'
import {
DeclarationField,
EastingNorthingField,
LatLongField,
NationalGridFieldNumberField,
Expand Down Expand Up @@ -216,6 +218,89 @@ describe('Location field formatting', () => {
})
})

describe('DeclarationField', () => {
let field: DeclarationField

beforeEach(() => {
const def: DeclarationFieldComponent = {
type: ComponentType.DeclarationField,
name: 'declField',
title: 'Declaration title',
content: '# markup heading',
options: {}
}
field = new DeclarationField(def, { model })
})

it('formats correctly when agreed', () => {
const state = {
declField: true
}

const answer = getAnswer(field, state, { format: 'email' })
expect(answer).toBe('I understand and agree\n')
})

it('formats correctly when not agreed', () => {
const state = {
declField: false
}

const answer = getAnswer(field, state, { format: 'email' })
expect(answer).toBe('Not provided\n')
})

it('formats for data output when agreed', () => {
const state = {
declField: true
}

const answer = getAnswer(field, state, { format: 'data' })
expect(answer).toBe('true')
})

it('formats for data output when not agreed', () => {
const state = {
declField: false
}

const answer = getAnswer(field, state, { format: 'data' })
expect(answer).toBe('false')
})

it('formats for data output when no value', () => {
const state = {}

const answer = getAnswer(field, state, { format: 'data' })
expect(answer).toBe('false')
})

it('formats for summary display when agreed', () => {
const state = {
declField: true
}

const answer = getAnswer(field, state, { format: 'summary' })
expect(answer).toBe('I understand and agree')
})

it('formats for summary display when not agreed', () => {
const state = {
declField: false
}

const answer = getAnswer(field, state, { format: 'summary' })
expect(answer).toBe('Not provided')
})

it('formats for summary display when no value', () => {
const state = {}

const answer = getAnswer(field, state, { format: 'summary' })
expect(answer).toBe('Not provided')
})
})

describe('getAnswerMarkdown', () => {
it('formats EastingNorthingField correctly', () => {
const def: EastingNorthingFieldComponent = {
Expand Down
53 changes: 51 additions & 2 deletions src/server/plugins/engine/models/SummaryViewModel.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import {
type FormDefinition,
type PageQuestion,
type RadiosFieldComponent
} from '@defra/forms-model'

import { FORM_PREFIX } from '~/src/server/constants.js'
import {
FormModel,
Expand Down Expand Up @@ -66,7 +72,7 @@ describe('SummaryViewModel', () => {
'Pizzas',
'Pizza'
],
values: ['Collection', 'Not supplied'],
values: ['Collection', 'Not provided'],
answers: ['Collection', ''],
names: ['orderType', 'pizza']
},
Expand Down Expand Up @@ -281,6 +287,49 @@ describe('SummaryViewModel', () => {
})
}
)

it('should use correct summary labels', () => {
request.query.force = '' // Preview URL '?force'
const state = {
$$__referenceNumber: 'foobar',
orderType: 'collection',
pizza: []
} satisfies FormState

// Setup an optional question
const definitionOptional = structuredClone(definition) as FormDefinition
const firstPage = definitionOptional.pages[0] as PageQuestion
const firstComponent = firstPage.components[0] as RadiosFieldComponent
firstComponent.options.required = false

const model = new FormModel(definitionOptional, {
basePath: `${FORM_PREFIX}/test`
})

context = model.getFormContext(request, state)

const page = createPage(model, definition.pages[2])

summaryViewModel = new SummaryViewModel(request, page, context)

expect(summaryViewModel.details).toHaveLength(2)

const [details1, details2] = summaryViewModel.details

expect(details1.items[0]).toMatchObject({
name: 'orderType',
value: 'Collection',
title: 'How you would like to receive your pizza (optional)',
label: 'How would you like to receive your pizza?'
})

expect(details2.items[0]).toMatchObject({
name: 'pizza',
value: '',
title: 'Pizzas',
label: 'Pizza'
})
})
})

describe('SummaryPageController', () => {
Expand Down Expand Up @@ -342,7 +391,7 @@ describe('SummaryPageController', () => {
)
})

it('should display default page title for v2 form when title not supplied', () => {
it('should display default page title for v2 form when title not provided', () => {
const state: FormState = {
$$__referenceNumber: 'foobar',
orderType: 'collection',
Expand Down
9 changes: 6 additions & 3 deletions src/server/plugins/engine/models/SummaryViewModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export class SummaryViewModel {
},
value: {
classes: 'app-prose-scope',
html: item.value || 'Not supplied'
html: item.value || 'Not provided'
},
actions: {
items
Expand Down Expand Up @@ -204,7 +204,7 @@ function ItemRepeat(
* Creates a form field detail item
* @see {@link DetailItemField}
*/
function ItemField(
export function ItemField(
page: PageControllerClass,
state: FormState,
field: Field,
Expand All @@ -216,7 +216,10 @@ function ItemField(
return {
name: field.name,
label: field.title,
title: field.label,
title:
field.options.required === false
? `${field.label} (optional)`
: field.label,
error: field.getFirstError(options.errors),
value: getAnswer(field, state),
href: getPageHref(page, options.path, {
Expand Down
Loading
Loading