Skip to content

Commit

Permalink
Merge pull request #151 from DEFRA/DSFAAP-639-generic-radio-buttons
Browse files Browse the repository at this point in the history
Dsfaap 639 generic radio buttons
  • Loading branch information
hughfdjackson authored Jan 24, 2025
2 parents 04cbc28 + ab42e31 commit a43d816
Show file tree
Hide file tree
Showing 32 changed files with 394 additions and 196 deletions.
3 changes: 2 additions & 1 deletion src/config/nunjucks/nunjucks.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ const nunjucksEnvironment = nunjucks.configure(
[
'node_modules/govuk-frontend/dist/',
path.resolve(dirname, '../../server/common/templates'),
path.resolve(dirname, '../../server/common/components')
path.resolve(dirname, '../../server/common/components'),
path.resolve(dirname, '../../server/common')
],
{
autoescape: true,
Expand Down
2 changes: 1 addition & 1 deletion src/server/check-answers/__snapshots__/index.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ exports[`#CheckAnswers Should provide expected response 1`] = `
How would you like this licence sent to you?
</dt>
<dd class="govuk-summary-list__value">
email
Email
</dd>
<dd class="govuk-summary-list__actions">
<a class="govuk-link" href="/receiving-the-licence/licence-email-or-post?redirect_uri=/submit/check-answers" data-testid="receiveMethod-change-link">Change<span class="govuk-visually-hidden"> How would you like this licence sent to you?</span></a>
Expand Down
9 changes: 5 additions & 4 deletions src/server/check-answers/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ const testAddress = {
addressPostcode: 'RG24 8RR'
}
const testEmailAddress = '[email protected]'
const testReceiveMethod = 'email'
const testReceiveMethodValue = 'email'
const testReceiveMethodLabel = 'Email'

const originDefaultState = {
onOffFarm: 'off',
Expand All @@ -30,7 +31,7 @@ const originDefaultState = {

const licenceDefaultState = {
emailAddress: testEmailAddress,
receiveMethod: testReceiveMethod,
receiveMethod: testReceiveMethodValue,
fullName: {
firstName: 'William T.',
lastName: 'Riker'
Expand Down Expand Up @@ -67,7 +68,7 @@ const emailContent = [
' ' +
licenceDefaultState.fullName.lastName,
'## How would you like this licence sent to you?',
testReceiveMethod,
testReceiveMethodLabel,
'## What email address would you like the licence sent to?',
testEmailAddress
].join('\n')
Expand Down Expand Up @@ -125,7 +126,7 @@ describe('#CheckAnswers', () => {
expect(taskListValues[5].innerHTML).toContain(
`${licenceDefaultState.fullName.firstName} ${licenceDefaultState.fullName.lastName}`
)
expect(taskListValues[6].innerHTML).toContain(testReceiveMethod)
expect(taskListValues[6].innerHTML).toContain(testReceiveMethodLabel)
expect(taskListValues[7].innerHTML).toContain(testEmailAddress)

expect(statusCode).toBe(statusCodes.ok)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export class QuestionPageController extends GenericPageController {
pageTitle: this.page.title,
heading: this.page.heading,
value: answer.value,
answer,
...this.page.viewProps(req)
})
}
Expand All @@ -74,6 +75,7 @@ export class QuestionPageController extends GenericPageController {
pageTitle: `Error: ${this.page.title}`,
heading: this.page.heading,
value: answer.value,
answer,
errors,
errorMessages: Answer.errorMessages(errors),
...this.page.viewProps(req)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -440,4 +440,68 @@ describe('QuestionPageController', () => {
expect(headers.location).toBe(`${overriddenQuestionUrl}?redirect=true`)
})
})

describe('View render', () => {
const h = {
view: jest.fn().mockReturnValue('view')
}
const request = {
yar: {
get: jest.fn(),
set: jest.fn()
},
query: {
redirect_uri: 'redirect_uri'
}
}

it('GET should render view with expected arguments', () => {
const result = controller.getHandler(request, h)

expect(h.view).toHaveBeenCalledTimes(1)
expect(h.view).toHaveBeenCalledWith(
questionView,
expect.objectContaining({
heading: question,
nextPage: 'redirect_uri',
pageTitle: question,
value: undefined
})
)

const viewArgs = h.view.mock.calls[0][1]
expect(viewArgs.answer).toBeInstanceOf(TestAnswer)

expect(result).toBe('view')
})

it('POST should render view with expected arguments', () => {
const postRequest = {
...request,
payload: { nextPage: 'test_next_page' }
}

const result = controller.postHandler(postRequest, h)

expect(h.view).toHaveBeenCalledTimes(1)
expect(h.view).toHaveBeenCalledWith(
questionView,
expect.objectContaining({
errorMessages: [
{ href: `#${questionKey}`, text: 'There is a problem' }
],
errors: { questionKey: { text: 'There is a problem' } },
heading: question,
nextPage: 'test_next_page',
pageTitle: `Error: ${question}`,
value: undefined
})
)

const viewArgs = h.view.mock.calls[0][1]
expect(viewArgs.answer).toBeInstanceOf(TestAnswer)

expect(result).toBe('view')
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@ const onOffFarmConfig = {
options: {
slaughter: { label: 'Slaughter' },
'dedicated-sale': { label: 'Dedicated sale for TB (orange market)' },
afu: { label: 'Approved finishing unit (AFU)' },
other: { label: 'Another destination' }
afu: {
label: 'Approved finishing unit (AFU)',
hint: 'Including enhanced with grazing (AFUE)'
},
other: {
label: 'Another destination',
hint: 'For example, a veterinary practice, zoo, or a laboratory'
}
},
errors: {
emptyOptionText: 'Select where the animals are going'
Expand Down
5 changes: 4 additions & 1 deletion src/server/common/model/answer/origin-type/origin-type.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ const config = {
payloadKey: 'originType',
options: {
'tb-restricted-farm': { label: 'TB restricted farm' },
afu: { label: 'Approved finishing unit (AFU)' },
afu: {
label: 'Approved finishing unit (AFU)',
hint: 'Including enhanced with grazing (AFUE)'
},
other: { label: 'Another type of premises' }
},
errors: {
Expand Down
19 changes: 19 additions & 0 deletions src/server/common/model/answer/radio-button/radio-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,23 @@ export class RadioButtonAnswer extends AnswerModel {
[this.config.payloadKey]: fields[this.config.payloadKey]
})
}

get viewModel() {
const items = Object.entries(this.config.options).map(([key, value]) => ({
id: key,
value: key,
text: value.label,
hint: {
text: value.hint
}
}))
items[0].id = this.config.payloadKey
return {
name: this.config.payloadKey,
id: this.config.payloadKey,
fieldset: {},
value: this.value,
items
}
}
}
2 changes: 2 additions & 0 deletions src/server/common/model/answer/radio-button/radio-button.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{% from "govuk/components/radios/macro.njk" import govukRadios %}
{{ govukRadios(assign({}, answer.viewModel, { errorMessage: errors[answer.config.payloadKey]})) }}
32 changes: 31 additions & 1 deletion src/server/common/model/answer/radio-button/radio-button.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const testRadioConfig = {
payloadKey: 'test_radio',
options: {
value_1: { label: 'test_label_1' },
value_2: { label: 'test_label_2' }
value_2: { label: 'test_label_2', hint: 'test_hint_2' }
},
errors: {
emptyOptionText: 'Select an option'
Expand Down Expand Up @@ -139,4 +139,34 @@ describe('RadioButton', () => {
expect(new RadioButtonTest(undefined).html).toBe('')
})
})

describe('#RadioButton.viewModel', () => {
it('should return everything (except errors) to render in the template', () => {
const answer = new RadioButtonTest({ test_radio: 'value_1' })
expect(answer.viewModel).toEqual({
name: 'test_radio',
id: 'test_radio',
fieldset: {},
value: answer.value,
items: [
{
id: 'test_radio',
value: 'value_1',
text: 'test_label_1',
hint: {
text: undefined
}
},
{
id: 'value_2',
value: 'value_2',
text: 'test_label_2',
hint: {
text: 'test_hint_2'
}
}
]
})
})
})
})
4 changes: 2 additions & 2 deletions src/server/common/model/answer/receiveMethod/receiveMethod.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { RadioButtonAnswer } from '../radio-button/radio-button.js'
const config = {
payloadKey: 'receiveMethod',
options: {
email: { label: 'email' },
post: { label: 'post' }
email: { label: 'Email' },
post: { label: 'Post' }
},
errors: {
emptyOptionText: 'Select how you would like this licence sent to you'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('ReceiveMethod', () => {

it('should have the expected options to select from', () => {
expect(Object.keys(ReceiveMethodAnswer.config.options)).toHaveLength(2)
expect(ReceiveMethodAnswer.config.options.email.label).toBe('email')
expect(ReceiveMethodAnswer.config.options.post.label).toBe('post')
expect(ReceiveMethodAnswer.config.options.email.label).toBe('Email')
expect(ReceiveMethodAnswer.config.options.post.label).toBe('Post')
})
})
2 changes: 1 addition & 1 deletion src/server/common/model/page/page-model.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class Page {
/**
* @param {import('@hapi/hapi').Request} _req
* @returns {Record<string, unknown>}
* */
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
viewProps(_req) {
return {}
Expand Down
45 changes: 45 additions & 0 deletions src/server/common/test-helpers/snapshot-page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { parseDocument } from '../../common/test-helpers/dom.js'
import { createServer } from '~/src/server/index.js'
import { withCsrfProtection } from './csrf.js'
/** @import { Server } from '@hapi/hapi' */

/* global expect, it, beforeAll, afterAll, describe */

/**
* @param {string} describeMessage
* @param {string} shouldMessage
* @param {string} urlPath
*/
export const describePageSnapshot = (
describeMessage,
shouldMessage,
urlPath
) => {
describe(describeMessage, () => {
/** @type {Server} */
let server

beforeAll(async () => {
server = await createServer()
await server.initialize()
})

afterAll(async () => {
await server.stop({ timeout: 0 })
})

it(shouldMessage, async () => {
const { payload } = await server.inject(
withCsrfProtection({
method: 'GET',
url: urlPath
})
)

const content =
parseDocument(payload).querySelector('#main-content')?.innerHTML

expect(content).toMatchSnapshot()
})
})
}
36 changes: 6 additions & 30 deletions src/server/cookies-policy/index.test.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,10 @@
import { createServer } from '~/src/server/index.js'
import { statusCodes } from '~/src/server/common/constants/status-codes.js'
import { parseDocument } from '~/src/server/common/test-helpers/dom.js'
import { describePageSnapshot } from '../common/test-helpers/snapshot-page.js'

describe('#destinationSummaryController', () => {
/** @type {Server} */
let server

beforeAll(async () => {
server = await createServer()
await server.initialize()
})

afterAll(async () => {
await server.stop({ timeout: 0 })
})

it('should render expected response and content', async () => {
const { payload, statusCode } = await server.inject({
method: 'GET',
url: '/cookies'
})

const document = parseDocument(payload)
expect(document.title).toBe('Cookies')
expect(statusCode).toBe(statusCodes.ok)

const content = document.querySelector('#main-content')?.innerHTML
expect(content).toMatchSnapshot()
})
})
describePageSnapshot(
'#destinationSummaryController',
'should render expected response and content',
'/cookies'
)

/**
* @import { Server } from '@hapi/hapi'
Expand Down
1 change: 0 additions & 1 deletion src/server/destination/another-destination/index.njk
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
{% from "govuk/components/radios/macro.njk" import govukRadios %}
{% extends 'layouts/page.njk' %}
{% block content %}
<div class="govuk-grid-row">
Expand Down
Loading

0 comments on commit a43d816

Please sign in to comment.