Skip to content

Commit

Permalink
Merge pull request #176 from DEFRA/DSFAAP-799-lift-text-template-into…
Browse files Browse the repository at this point in the history
…-answer

DSFAAP-799:  lift text template into answer
  • Loading branch information
hughfdjackson authored Jan 31, 2025
2 parents f5714d8 + d48d216 commit 63f4850
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 41 deletions.
6 changes: 6 additions & 0 deletions src/server/common/model/answer/cph-number/cph-number.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { TextAnswer } from '../text/text.js'

/** @import { TextConfig } from '../text/text.js' */

const cphNumberRegex = /^(\d{2})\/(\d{3})\/(\d{4})$/i

const invalidCphNumberError =
Expand All @@ -15,9 +17,13 @@ const emptyCphNumberError = 'Enter the farm or premises CPH number'
* @augments {TextAnswer<CphNumberPayload>}
*/
export class CphNumberAnswer extends TextAnswer {
/** @type {TextConfig} */
static config = {
payloadKey: 'cphNumber',
stripWhitespace: true,
autocomplete: 'cph-number',
characterWidth: 10,
hint: 'For example, 12/345/6789',
validation: {
maxLength: { value: 11, message: invalidCphNumberError },
pattern: { regex: cphNumberRegex, message: invalidCphNumberError },
Expand Down
7 changes: 7 additions & 0 deletions src/server/common/model/answer/email/email-address.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { TextAnswer } from '../text/text.js'

/** @import {TextConfig} from '../text/text.js' */

const emailAddressRegex = /^[^@]+@[^@]+$/

const maxLength = 255
Expand All @@ -17,9 +19,14 @@ const invalidAddressError =
* @augments {TextAnswer<EmailAddressPayload>}
*/
export class EmailAddressAnswer extends TextAnswer {
/** @type {TextConfig} */
static config = {
payloadKey: 'emailAddress',
stripWhitespace: true,
type: 'email',
spellcheck: false,
autocomplete: 'email-address',
characterWidth: 20,
validation: {
pattern: { regex: emailAddressRegex, message: invalidAddressError },
maxLength: { value: maxLength, message: invalidAddressError },
Expand Down
46 changes: 46 additions & 0 deletions src/server/common/model/answer/text/text.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { AnswerModel } from '../answer-model.js'
import { validateAnswerAgainstSchema } from '../validation.js'
import { NotImplementedError } from '../../../helpers/not-implemented-error.js'

/** @import {AnswerViewModelOptions} from '../answer-model.js' */

/**
* @param {TextConfig} config
* @returns {Joi.Schema}
Expand Down Expand Up @@ -39,6 +41,11 @@ const whitespaceRegex = /\s+/g
* export @typedef {{
* payloadKey: string,
* stripWhitespace?: boolean,
* type?: 'email', // the default is text, so no need to specify
* spellcheck?: false,
* characterWidth?: 10 | 20,
* autocomplete?: string,
* hint?: string,
* validation: {
* maxLength: { value: number, message: string },
* empty: { message: string },
Expand Down Expand Up @@ -98,6 +105,45 @@ export class TextAnswer extends AnswerModel {
)
}

/**
* @param {AnswerViewModelOptions} options
*/
viewModel({ validate }) {
const { payloadKey, type, spellcheck, autocomplete, characterWidth, hint } =
this.config
const viewModel = {
id: payloadKey,
name: payloadKey,
value: this.value
}

if (characterWidth) {
viewModel.classes = `govuk-input--width-${characterWidth}`
}

if (autocomplete) {
viewModel.autocomplete = autocomplete
}

if (type) {
viewModel.type = type
}

if (hint) {
viewModel.hint = { text: hint }
}

if (spellcheck === false) {
viewModel.spellcheck = false
}

if (validate) {
viewModel.errorMessage = this.validate().errors[payloadKey]
}

return viewModel
}

/**
* @param {Payload} fields
*/
Expand Down
6 changes: 6 additions & 0 deletions src/server/common/model/answer/text/text.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{% from "govuk/components/input/macro.njk" import govukInput %}
{% from "govuk/components/fieldset/macro.njk" import govukFieldset %}

{% call govukFieldset() %}
{{ govukInput(answer.viewModel(viewModelOptions)) }}
{% endcall %}
76 changes: 74 additions & 2 deletions src/server/common/model/answer/text/text.test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { TextAnswer } from './text.js'
/** @import {TextConfig} from './text.js' */

const maxLengthError = 'Text exceeds maximum length (40)'

/** @type {TextConfig} */
const textConfig = {
payloadKey: 'textPayload',
validation: {
maxLength: { value: 40, message: 'Text exceeds maximum length (40)' },
maxLength: { value: 40, message: maxLengthError },
empty: { message: 'Text must not be empty' }
}
}
Expand All @@ -25,6 +27,11 @@ const validPayload = {
textPayload: 'some text'
}

const longAnswer = new Array(41).fill('a').join('')
const invalidPayload = {
textPayload: longAnswer
}

describe('TextAnswer.new', () => {
it('should strip away any irrelevant values', () => {
const payload = { ...validPayload, nextPage: '/other/page' }
Expand All @@ -37,7 +44,7 @@ describe('TextAnswer.new', () => {
describe('TextAnswer.validate', () => {
it('should error if max length is exceeded', () => {
const textAnswer = new TestTextAnswer({
textPayload: new Array(41).fill('a').join('')
textPayload: longAnswer
})
const { isValid, errors } = textAnswer.validate()

Expand Down Expand Up @@ -220,3 +227,68 @@ describe('TestAnswer.html', () => {
expect(textAnswer.html).toBe('')
})
})

describe('TestAnswer.viewModel (without any extra options)', () => {
const textAnswer = new TestTextAnswer(invalidPayload)

it('should return data to render without errors (if validate is false)', () => {
expect(textAnswer.viewModel({ validate: false })).toEqual({
id: 'textPayload',
name: 'textPayload',
value: textAnswer.value
})
})

it('should return data to render with errors (if validate is true)', () => {
expect(textAnswer.viewModel({ validate: true })).toEqual({
id: 'textPayload',
name: 'textPayload',
value: textAnswer.value,
errorMessage: { text: maxLengthError }
})
})
})

describe('TestAnswer.viewModel (with all optional options)', () => {
/** @type {TextConfig} */
const textConfigWithExtraOptions = {
...textConfig,
type: 'email',
autocomplete: 'email-address',
spellcheck: false,
characterWidth: 20,
hint: 'Enter your email'
}

class ExtraOptionsTextAnswer extends TextAnswer {
static config = textConfigWithExtraOptions
}
const textAnswer = new ExtraOptionsTextAnswer(invalidPayload)

it('should return data to render without errors (if validate is false)', () => {
expect(textAnswer.viewModel({ validate: false })).toEqual({
id: 'textPayload',
name: 'textPayload',
type: 'email',
hint: { text: 'Enter your email' },
spellcheck: false,
autocomplete: 'email-address',
classes: 'govuk-input--width-20',
value: textAnswer.value
})
})

it('should return data to render with errors (if validate is true)', () => {
expect(textAnswer.viewModel({ validate: true })).toEqual({
id: 'textPayload',
name: 'textPayload',
type: 'email',
hint: { text: 'Enter your email' },
spellcheck: false,
autocomplete: 'email-address',
classes: 'govuk-input--width-20',
value: textAnswer.value,
errorMessage: { text: maxLengthError }
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ exports[`EmailAddressPage EmailAddressPage.content should render expected respon
<input type="hidden" name="nextPage" value="">
<fieldset class="govuk-fieldset">
<div class="govuk-form-group">
<div class="govuk-form-group">
<input class="govuk-input govuk-input--width-20" id="emailAddress" name="emailAddress" type="email" spellcheck="false" autocomplete="email-address">
</div>
Expand Down
19 changes: 1 addition & 18 deletions src/server/licence/email-address/index.njk
Original file line number Diff line number Diff line change
@@ -1,22 +1,5 @@
{% from "govuk/components/input/macro.njk" import govukInput %}
{% from "govuk/components/fieldset/macro.njk" import govukFieldset %}
{% extends 'layouts/questions.njk' %}

{% block questions %}

{% call govukFieldset() %}

{{
govukInput({
id: "emailAddress",
name: "emailAddress",
type: "email",
spellcheck: false,
autocomplete: "email-address",
classes: "govuk-input--width-20",
value: value,
errorMessage: errors.emailAddress
})
}}
{% endcall %}
{% include "model/answer/text/text.njk" %}
{% endblock %}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ exports[`CphNumberPage #cphNumberPage.content licenceSummaryPage.content should
<input type="hidden" name="nextPage" value="">
<fieldset class="govuk-fieldset">
<div class="govuk-form-group">
<div class="govuk-form-group">
<div id="cphNumber-hint" class="govuk-hint">
For example, 12/345/6789
Expand Down
19 changes: 1 addition & 18 deletions src/server/origin/cph-number/index.njk
Original file line number Diff line number Diff line change
@@ -1,22 +1,5 @@
{% from "govuk/components/input/macro.njk" import govukInput %}
{% from "govuk/components/fieldset/macro.njk" import govukFieldset %}
{% extends 'layouts/questions.njk' %}

{% block questions %}

{% call govukFieldset() %}
{{
govukInput({
id: "cphNumber",
name: "cphNumber",
autocomplete: "cph-number",
classes: "govuk-input--width-10",
value: value,
errorMessage: errors.cphNumber,
hint: {
text: "For example, 12/345/6789"
}
})
}}
{% endcall %}
{% include "model/answer/text/text.njk" %}
{% endblock %}

0 comments on commit 63f4850

Please sign in to comment.