Skip to content

Commit

Permalink
Merge pull request #74 from DEFRA/DSFAAP-511_destination-where-are-th…
Browse files Browse the repository at this point in the history
…e-animals-going-page

DSFAAP-511: Destination type page
  • Loading branch information
eoin-corr-git authored Dec 16, 2024
2 parents 3488ba6 + 8abe2b1 commit 2584be2
Show file tree
Hide file tree
Showing 25 changed files with 706 additions and 134 deletions.
71 changes: 71 additions & 0 deletions src/server/common/model/answer/destination-type.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import Joi from 'joi'
import { AnswerModel } from './answer-model.js'
import { validateAnswerAgainstSchema } from './validation.js'

const selectOptionText = 'Select where the animals are going'

export const destinationTypePayloadSchema = Joi.object({
destinationType: Joi.string()
.required()
.valid('slaughter', 'dedicated-sale', 'afu', 'other')
.messages({
'any.required': selectOptionText,
'any.valid': selectOptionText,
'string.empty': selectOptionText
})
})

/**
* export @typedef {'slaughter' | 'dedicated-sale' | 'afu' | 'other'} DestinationTypeData
* @typedef {{ destinationType: DestinationTypeData }} DestinationTypePayload
*/

/**
* @augments AnswerModel<DestinationTypePayload>
*/
export class DestinationType extends AnswerModel {
/**
* @returns {DestinationTypeData | undefined}
*/
toState() {
return this._data?.destinationType
}

get value() {
return this._data?.destinationType
}

get html() {
const destinationType = this._data?.destinationType

const destinationTypeMapping = {
slaughter: 'Slaughter',
'dedicated-sale': 'Dedicated sale for TB (orange market)',
afu: 'Approved finishing unit (AFU)',
other: 'Another destination'
}

return destinationTypeMapping[destinationType] ?? ''
}

/**
* @param {DestinationTypeData | undefined} state
* @returns {DestinationType}
*/
static fromState(state) {
return new DestinationType(
state !== undefined ? { destinationType: state } : undefined
)
}

validate() {
return validateAnswerAgainstSchema(
destinationTypePayloadSchema,
this._data ?? {}
)
}

_extractFields({ destinationType }) {
return { destinationType }
}
}
144 changes: 144 additions & 0 deletions src/server/common/model/answer/destination-type.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { DestinationType } from './destination-type.js'
/** @import {DestinationTypePayload} from './destination-type.js' */

/** @type {DestinationTypePayload} */
const validDestinationTypeRadio = {
destinationType: 'slaughter'
}

describe('DestinationType', () => {
describe('#DestinationType.new', () => {
it('should strip away any irrelevant values', () => {
const payload = { ...validDestinationTypeRadio, nextPage: '/other/page' }
const destinationType = new DestinationType(payload)

expect(destinationType._data).toEqual(validDestinationTypeRadio)
})
})

describe('#DestinationType.validate', () => {
it('should return true for slaughter', () => {
const { isValid, errors } = new DestinationType({
destinationType: 'slaughter'
}).validate()

expect(isValid).toBe(true)
expect(errors).toEqual({})
})

it('should return true for dedicated-sale', () => {
const { isValid, errors } = new DestinationType({
destinationType: 'dedicated-sale'
}).validate()

expect(isValid).toBe(true)
expect(errors).toEqual({})
})

it('should return true for afu', () => {
const { isValid, errors } = new DestinationType({
destinationType: 'afu'
}).validate()

expect(isValid).toBe(true)
expect(errors).toEqual({})
})

it('should return true for other', () => {
const { isValid, errors } = new DestinationType({
destinationType: 'other'
}).validate()

expect(isValid).toBe(true)
expect(errors).toEqual({})
})

it('should return false for empty', () => {
const { isValid, errors } = new DestinationType(undefined).validate()

expect(isValid).toBe(false)
expect(errors.destinationType.text).toBe(
'Select where the animals are going'
)
})
})

describe('#DestinationType.toState', () => {
it('should replace missing data with blank string', () => {
const data = new DestinationType().toState()

expect(data).toBeUndefined()
})

it('should pass through valid data unaltered', () => {
const data = new DestinationType(validDestinationTypeRadio).toState()

expect(data).toBe(validDestinationTypeRadio.destinationType)
})
})

describe('DestinationType.fromState', () => {
it('should return just the destinationType value from the payload', () => {
const state = new DestinationType(validDestinationTypeRadio).toState()
expect(DestinationType.fromState(state)._data).toEqual(
validDestinationTypeRadio
)
})

it('should return an undefined value if the state is undefined', () => {
expect(DestinationType.fromState(undefined).value).toBeUndefined()
})

it('should store undefined if the state is undefined', () => {
expect(DestinationType.fromState(undefined)._data).toBeUndefined()
})
})

describe('#DestinationType.value', () => {
it('should return a value-wrapped object to rendering in the template', () => {
expect(
new DestinationType({
destinationType: 'slaughter'
}).value
).toBe('slaughter')
})
})

describe('#DestinationType.html', () => {
it('should return the full text for `slaughter`', () => {
expect(
new DestinationType({
destinationType: 'slaughter'
}).html
).toBe('Slaughter')
})

it('should return the full text for `dedicated-sale`', () => {
expect(
new DestinationType({
destinationType: 'dedicated-sale'
}).html
).toBe('Dedicated sale for TB (orange market)')
})

it('should return the full text for `afu`', () => {
expect(
new DestinationType({
destinationType: 'afu'
}).html
).toBe('Approved finishing unit (AFU)')
})

it('should return the full text for `other`', () => {
expect(
new DestinationType({
destinationType: 'other'
}).html
).toBe('Another destination')
})

it('should return an empty string for undefined', () => {
expect(new DestinationType(undefined).html).toBe('')
})
})
})
118 changes: 53 additions & 65 deletions src/server/common/model/answer/on-off-farm.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,90 +6,78 @@ const validOnOffRadio = {
onOffFarm: 'on'
}

describe('OnOffFarm.new', () => {
it('should strip away any irrelevant values', () => {
const payload = { ...validOnOffRadio, nextPage: '/other/page' }
const onOffFarm = new OnOffFarm(payload)
describe('OnOffFarm', () => {
describe('OnOffFarm.new', () => {
it('should strip away any irrelevant values', () => {
const payload = { ...validOnOffRadio, nextPage: '/other/page' }
const onOffFarm = new OnOffFarm(payload)

expect(onOffFarm._data).toEqual(validOnOffRadio)
})
})

describe('#OnOffFarm.validate', () => {
test('should return true for on', () => {
const { isValid, errors } = new OnOffFarm({
onOffFarm: 'on'
}).validate()

expect(isValid).toBe(true)
expect(errors).toEqual({})
expect(onOffFarm._data).toEqual(validOnOffRadio)
})
})

test('should return true for off', () => {
const { isValid, errors } = new OnOffFarm({
onOffFarm: 'off'
}).validate()
describe('#OnOffFarm.validate', () => {
test('should return true for on', () => {
const { isValid, errors } = new OnOffFarm({
onOffFarm: 'on'
}).validate()

expect(isValid).toBe(true)
expect(errors).toEqual({})
})
expect(isValid).toBe(true)
expect(errors).toEqual({})
})

test('should return false for empty', () => {
const { isValid, errors } = new OnOffFarm(undefined).validate()
test('should return true for off', () => {
const { isValid, errors } = new OnOffFarm({
onOffFarm: 'off'
}).validate()

expect(isValid).toBe(false)
expect(errors.onOffFarm.text).toBe(
'Select if you are moving cattle on or off your farm or premises'
)
})
})
expect(isValid).toBe(true)
expect(errors).toEqual({})
})

describe('#OnOffFarm.toState', () => {
test('should replace missing data with blank string', () => {
const data = new OnOffFarm().toState()
test('should return false for empty', () => {
const { isValid, errors } = new OnOffFarm(undefined).validate()

expect(data).toBeUndefined()
expect(isValid).toBe(false)
expect(errors.onOffFarm.text).toBe(
'Select if you are moving cattle on or off your farm or premises'
)
})
})

test('should pass through valid data unaltered', () => {
const data = new OnOffFarm({ onOffFarm: 'on' }).toState()
describe('#OnOffFarm.toState', () => {
test('should replace missing data with blank string', () => {
const data = new OnOffFarm().toState()

expect(data).toBe('on')
})
})
expect(data).toBeUndefined()
})

describe('OnOffFarm.fromState', () => {
it('should return just the onOffFarm value from the payload', () => {
const state = new OnOffFarm(validOnOffRadio).toState()
expect(OnOffFarm.fromState(state)._data).toEqual(validOnOffRadio)
})
test('should pass through valid data unaltered', () => {
const data = new OnOffFarm({ onOffFarm: 'on' }).toState()

it('should return an undefined value if the state is undefined', () => {
expect(OnOffFarm.fromState(undefined).value).toBeUndefined()
expect(data).toBe('on')
})
})

it('should store undefined if the state is undefined', () => {
expect(OnOffFarm.fromState(undefined)._data).toBeUndefined()
})
})
describe('OnOffFarm.fromState', () => {
it('should return just the onOffFarm value from the payload', () => {
const state = new OnOffFarm(validOnOffRadio).toState()
expect(OnOffFarm.fromState(state)._data).toEqual(validOnOffRadio)
})

describe('#OnOffFarm.value', () => {
it('should return a value-wrapped object to rendering in the template', () => {
expect(new OnOffFarm({ onOffFarm: 'on' }).value).toBe('on')
})
})
it('should return an undefined value if the state is undefined', () => {
expect(OnOffFarm.fromState(undefined).value).toBeUndefined()
})

describe('#OnOffFarm.html', () => {
it('should return the full text for `on`', () => {
expect(new OnOffFarm({ onOffFarm: 'on' }).html).toBe(
'On to the farm or premises'
)
it('should store undefined if the state is undefined', () => {
expect(OnOffFarm.fromState(undefined)._data).toBeUndefined()
})
})

it('should return the full text for `off`', () => {
expect(new OnOffFarm({ onOffFarm: 'off' }).html).toBe(
'Off the farm or premises'
)
describe('#OnOffFarm.value', () => {
it('should return a value-wrapped object to rendering in the template', () => {
expect(new OnOffFarm({ onOffFarm: 'on' }).value).toBe('on')
})
})

describe('#OnOffFarm.html', () => {
Expand Down
25 changes: 20 additions & 5 deletions src/server/common/model/section/destination.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
import { SectionModel } from './section-model/section-model.js'
import { SectionModel } from '../section/section-model/index.js'
import { destinationTypePage } from '~/src/server/destination/destination-type/index.js'

/**
* export @typedef {{
* destinationType: DestinationTypeData | undefined;
* }} DestinationData
* @import {DestinationTypeData} from '../answer/destination-type.js'
*/
export class Destination extends SectionModel {
validate() {
return { isValid: false, result: {} }
firstPage = destinationTypePage

get destinationType() {
return this._data?.destinationType.answer
}

/**
* @param {DestinationData | undefined} state
* @returns {Destination}
*/
static fromState() {
return new Destination()
static fromState(state) {
return new Destination({
destinationType: {
page: destinationTypePage,
answer: destinationTypePage.Answer.fromState(state?.destinationType)
}
})
}
}
Loading

0 comments on commit 2584be2

Please sign in to comment.