-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add new billing account change address validator (#383)
https://eaflood.atlassian.net/browse/WATER-4092 We use validators to 'validate' incoming payloads. This new validator will be used to check the content of a request to our new `/billing-accounts/{id}/change-address` endpoint. Though the journey in the UI starts with clicking a **Change address** button during the process you can also change the company and contact linked to the billing account as well. This is why we need to cater for all 3 possibly being sent in the payload. The [Joi](https://joi.dev/) schema we've compiled comes from what we found is currently being used in the legacy code (`water-abstraction-service/src/modules/invoice-accounts/routes.js`).
- Loading branch information
1 parent
35d116d
commit 9f7e07c
Showing
3 changed files
with
320 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
'use strict' | ||
|
||
/** | ||
* @module ChangeAddressValidator | ||
*/ | ||
|
||
const Joi = require('joi') | ||
|
||
const StaticLookupsLib = require('../lib/static-lookups.lib.js') | ||
|
||
/** | ||
* Checks that the payload of a `/billing-accounts/{invoiceAccountId}/address` request is valid | ||
* | ||
* The JOI schema was interpreted from what we found in water-abstraction-service/src/modules/invoice-accounts/routes.js | ||
* | ||
* @param {Object} data The data to be validated (assumed to be the request payload) | ||
* | ||
* @returns {Object} the result from calling Joi's schema.validate(). It will be an object with a `value:` property. If | ||
* any errors are found the `error:` property will also exist detailing what the issues were | ||
*/ | ||
function go (data) { | ||
const schema = Joi.object({ | ||
address: _addressSchema(), | ||
agentCompany: _agentCompanySchema(), | ||
contact: _contactSchema() | ||
}) | ||
|
||
return schema.validate(data) | ||
} | ||
|
||
function _addressSchema () { | ||
return Joi.object({ | ||
id: Joi.string().guid().optional(), | ||
addressLine1: Joi.string().optional(), | ||
addressLine2: Joi.string().optional(), | ||
addressLine3: Joi.string().optional(), | ||
addressLine4: Joi.string().optional(), | ||
town: Joi.string().optional(), | ||
county: Joi.string().optional(), | ||
country: Joi.string().optional(), | ||
postcode: Joi.string().optional(), | ||
uprn: Joi.number().optional(), | ||
source: Joi.string().optional() | ||
}).required() | ||
} | ||
|
||
function _agentCompanySchema () { | ||
return Joi.object({ | ||
id: Joi.string().guid().optional(), | ||
type: Joi.string().valid(...StaticLookupsLib.companyTypes).optional(), | ||
organisationType: Joi.string().valid(...StaticLookupsLib.organisationTypes).optional(), | ||
name: Joi.string().optional(), | ||
companyNumber: Joi.string().optional() | ||
}).optional() | ||
} | ||
|
||
function _contactSchema () { | ||
return Joi.object({ | ||
id: Joi.string().guid().optional(), | ||
type: Joi.string().valid(...StaticLookupsLib.contactTypes).optional(), | ||
salutation: Joi.string().optional(), | ||
firstName: Joi.string().optional(), | ||
initials: Joi.string().optional(), | ||
middleInitials: Joi.string().optional(), | ||
lastName: Joi.string().optional(), | ||
suffix: Joi.string().optional(), | ||
department: Joi.string().optional(), | ||
source: Joi.string().valid(...StaticLookupsLib.sources).optional(), | ||
isTest: Joi.boolean().default(false).optional() | ||
}).optional() | ||
} | ||
|
||
module.exports = { | ||
go | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,218 @@ | ||
'use strict' | ||
|
||
// Test framework dependencies | ||
const Lab = require('@hapi/lab') | ||
const Code = require('@hapi/code') | ||
|
||
const { describe, it, beforeEach } = exports.lab = Lab.script() | ||
const { expect } = Code | ||
|
||
// Thing under test | ||
const ChangeAddressValidator = require('../../app/validators/change-address.validator.js') | ||
|
||
describe('Create Bill Run validator', () => { | ||
const completeAddress = { | ||
id: '752446c0-a649-4383-967c-4e4fb6e13dde', | ||
addressLine1: 'Building 12', | ||
addressLine2: 'SCP Headquarters', | ||
addressLine3: 'East campus', | ||
addressLine4: '227 Roundly Rd', | ||
town: 'Leeds', | ||
county: 'West Yorkshire', | ||
country: 'United Kingdom', | ||
postcode: 'LS8 4HS', | ||
uprn: 97564, | ||
source: 'ea-address-facade' | ||
} | ||
const completeAgentCompany = { | ||
id: 'aa0dd66a-6f38-4ea6-b2e1-9639cb51c792', | ||
type: 'organisation', | ||
organisationType: 'limitedCompany', | ||
name: 'SCP', | ||
companyNumber: 'OE008471' | ||
} | ||
const completeContact = { | ||
id: '9969a9e6-c440-4065-ba2c-16566cb59575', | ||
type: 'person', | ||
salutation: 'Mrs', | ||
firstName: 'Margherita', | ||
middleInitials: 'OE008471', | ||
lastName: 'Villar', | ||
suffix: 'MBE', | ||
department: 'Humanoid Risk Assessment', | ||
source: 'wrls', | ||
isTest: false | ||
} | ||
|
||
let data | ||
|
||
describe('when valid data is provided', () => { | ||
describe('and it is the minimalist valid data allowed', () => { | ||
beforeEach(() => { | ||
data = { | ||
address: {} | ||
} | ||
}) | ||
|
||
it('confirms the data is valid', () => { | ||
const result = ChangeAddressValidator.go(data) | ||
|
||
expect(result.value).to.exist() | ||
expect(result.error).not.to.exist() | ||
}) | ||
}) | ||
|
||
describe('which includes only a valid address', () => { | ||
beforeEach(() => { | ||
data = { | ||
address: { | ||
...completeAddress | ||
} | ||
} | ||
}) | ||
|
||
it('confirms the data is valid', () => { | ||
const result = ChangeAddressValidator.go(data) | ||
|
||
expect(result.value).to.exist() | ||
expect(result.error).not.to.exist() | ||
expect(result.value.address.id).to.equal(data.address.id) | ||
}) | ||
}) | ||
|
||
describe('which includes a minimal address and a valid agent company', () => { | ||
beforeEach(() => { | ||
data = { | ||
agentCompany: { | ||
...completeAgentCompany | ||
}, | ||
address: {} | ||
} | ||
}) | ||
|
||
it('confirms the data is valid', () => { | ||
const result = ChangeAddressValidator.go(data) | ||
|
||
expect(result.value).to.exist() | ||
expect(result.error).not.to.exist() | ||
expect(result.value.agentCompany.id).to.equal(data.agentCompany.id) | ||
}) | ||
}) | ||
|
||
describe('which includes a minimal address and a valid contact', () => { | ||
beforeEach(() => { | ||
data = { | ||
contact: { | ||
...completeContact | ||
}, | ||
address: {} | ||
} | ||
}) | ||
|
||
it('confirms the data is valid', () => { | ||
const result = ChangeAddressValidator.go(data) | ||
|
||
expect(result.value).to.exist() | ||
expect(result.error).not.to.exist() | ||
expect(result.value.contact.id).to.equal(data.contact.id) | ||
}) | ||
}) | ||
}) | ||
|
||
describe('when invalid data is provided', () => { | ||
describe("because no 'address' is provided", () => { | ||
beforeEach(() => { | ||
data = { | ||
agentCompany: {}, | ||
contact: {} | ||
} | ||
}) | ||
|
||
it('returns an error', () => { | ||
const result = ChangeAddressValidator.go(data) | ||
|
||
expect(result.value).to.exist() | ||
expect(result.error).to.exist() | ||
expect(result.error.details[0].message).to.equal('"address" is required') | ||
}) | ||
}) | ||
|
||
describe('and the issue is in the agent company', () => { | ||
beforeEach(() => { | ||
data = { | ||
agentCompany: { | ||
...completeAgentCompany | ||
}, | ||
address: {} | ||
} | ||
}) | ||
|
||
describe("because 'type' is unrecognised", () => { | ||
beforeEach(() => { | ||
data.agentCompany.type = 'INVALID' | ||
}) | ||
|
||
it('returns an error', () => { | ||
const result = ChangeAddressValidator.go(data) | ||
|
||
expect(result.value).to.exist() | ||
expect(result.error).to.exist() | ||
expect(result.error.details[0].message).startsWith('"agentCompany.type" must be one of') | ||
}) | ||
}) | ||
|
||
describe("because 'organisationType' is unrecognised", () => { | ||
beforeEach(() => { | ||
data.agentCompany.organisationType = 'INVALID' | ||
}) | ||
|
||
it('returns an error', () => { | ||
const result = ChangeAddressValidator.go(data) | ||
|
||
expect(result.value).to.exist() | ||
expect(result.error).to.exist() | ||
expect(result.error.details[0].message).startsWith('"agentCompany.organisationType" must be one of') | ||
}) | ||
}) | ||
}) | ||
|
||
describe('and it is an issue in the contact', () => { | ||
beforeEach(() => { | ||
data = { | ||
contact: { | ||
...completeContact | ||
}, | ||
address: {} | ||
} | ||
}) | ||
|
||
describe("because 'type' is unrecognised", () => { | ||
beforeEach(() => { | ||
data.contact.type = 'INVALID' | ||
}) | ||
|
||
it('returns an error', () => { | ||
const result = ChangeAddressValidator.go(data) | ||
|
||
expect(result.value).to.exist() | ||
expect(result.error).to.exist() | ||
expect(result.error.details[0].message).startsWith('"contact.type" must be one of') | ||
}) | ||
}) | ||
|
||
describe("because 'source' is unrecognised", () => { | ||
beforeEach(() => { | ||
data.contact.source = 'INVALID' | ||
}) | ||
|
||
it('returns an error', () => { | ||
const result = ChangeAddressValidator.go(data) | ||
|
||
expect(result.value).to.exist() | ||
expect(result.error).to.exist() | ||
expect(result.error.details[0].message).startsWith('"contact.source" must be one of') | ||
}) | ||
}) | ||
}) | ||
}) | ||
}) |