Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/fcrm 5441 #456

Merged
merged 10 commits into from
Jan 28, 2025
18 changes: 0 additions & 18 deletions .jest/setup.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,17 @@
jest.mock('../config/environment')
const createServer = require('../server')
const ORIGINAL_ENV = process.env
const CONSOLE_ERROR = console.error
const CONSOLE_LOG = console.log
const DEV_NULL_LOG = () => {}
let server

beforeEach(async () => {
jest.resetAllMocks()
// add any common mockage here, eg json POSTs
server = await createServer()
await server.initialize()
if (process.env.NOLOG) {
console.log = DEV_NULL_LOG
console.error = DEV_NULL_LOG
}
})

afterEach(async () => {
try {
if (server) {
await server.stop()
}
} finally {
// reset environment variables after test
process.env = { ...ORIGINAL_ENV }
}
console.log = CONSOLE_LOG
console.error = CONSOLE_ERROR
})

const getServer = () => server

export { getServer }
35 changes: 33 additions & 2 deletions __mocks__/@esri/arcgis-rest-request.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

let expectedParameters
const response = {
token: 'TEST_TOKEN',
refreshToken: () => {
@@ -14,4 +14,35 @@ const ApplicationCredentialsManager = {
fromCredentials: () => (response)
}

module.exports = { ApplicationCredentialsManager, _invalidateToken, _resetToken }
const requestSpy = {
expectParameters: (params) => { expectedParameters = params }
}

const request = async (url, requestObject) => {
if (expectedParameters) {
expect(url).toEqual(expectedParameters.url)
expect(requestObject).toEqual(expectedParameters.requestObject)
}
return {
layers: [
{
id: 0,
count: 0
}, {
id: 1,
count: 0
}, {
id: 2,
count: 0
}
]
}
}

module.exports = {
ApplicationCredentialsManager,
_invalidateToken,
_resetToken,
request,
requestSpy
}
5 changes: 1 addition & 4 deletions config/.env-example
Original file line number Diff line number Diff line change
@@ -27,10 +27,7 @@ placeApiUrl=http://dummyuri
agolClientId=TEST_AGOL_CLIENT_ID
agolClientSecret=TEST_AGOL_CLIENT_SECRET
agolServiceId=DUMMY_SERVICE_ID
agolCustomerTeamEndPoint=/Flood_Map_for_Planning_Query_Service_NON_PRODUCTION/FeatureServer/0
agolLocalAuthorityEndPoint=/Flood_Map_for_Planning_Query_Service_NON_PRODUCTION/FeatureServer/1
agolIsEnglandEndPoint=/Flood_Map_for_Planning_Query_Service_NON_PRODUCTION/FeatureServer/2
agolFloodZonesRiversAndSeaEndPoint=/Flood_Zones_2_and_3_Rivers_and_Sea_NON_PRODUCTION/FeatureServer/0

#EA Maps
eamapsServiceUrl=http://dummyEAMapslUrl
eamapsProduct1User=PRODUCT1_USER
72 changes: 69 additions & 3 deletions config/__tests__/config.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
const { toBool } = require('../toBool')

describe('Ensure config is correct', () => {
beforeEach(() => {
jest.resetModules()
})
it('test config', () => {
expect(() => {
require('../index')
@@ -41,7 +44,72 @@ describe('Ensure config is correct', () => {
customerTeamEndPoint: '/Flood_Map_for_Planning_Query_Service_NON_PRODUCTION/FeatureServer/0',
localAuthorityEndPoint: '/Flood_Map_for_Planning_Query_Service_NON_PRODUCTION/FeatureServer/1',
isEnglandEndPoint: '/Flood_Map_for_Planning_Query_Service_NON_PRODUCTION/FeatureServer/2',
floodZonesRiversAndSeaEndPoint: '/Flood_Zones_2_and_3_Rivers_and_Sea_NON_PRODUCTION/FeatureServer/0'
floodZonesRiversAndSeaEndPoint: '/Flood_Zones_2_and_3_Rivers_and_Sea_NON_PRODUCTION/FeatureServer/0',
riversAndSeaDefendedEndPoint: '/Rivers_and_Sea_Defended_Depth_NON_PRODUCTION/FeatureServer',
riversAndSeaUndefendedEndPoint: '/Rivers_and_Sea_Undefended_Depth_NON_PRODUCTION/FeatureServer',
riversAndSeaDefendedCCP1EndPoint: '/Rivers_and_Sea_Defended_Depth_CCP1_NON_PRODUCTION/FeatureServer',
riversAndSeaUndefendedCCP1EndPoint: '/Rivers_and_Sea_Undefended_Depth_CCP1_NON_PRODUCTION/FeatureServer',
surfaceWaterEndPoint: '/Risk_of_Flooding_from_Surface_Water_Depth_0mm_NON_PRODUCTION/FeatureServer/0'
},
eamaps: {
serviceUrl: 'http://dummyEAMapslUrl',
product1User: 'PRODUCT1_USER',
product1Password: 'PRODUCT1_PASSWORD',
product1EndPoint: '/rest/services/FMfP/FMFPGetProduct1/GPServer/fmfp_get_product1/execute',
tokenEndPoint: '/tokens/generateToken'
},
defraMap: {
layerNameSuffix: '_NON_PRODUCTION'
},
riskAdminApi: {
url: 'http://riskadmin-api-url'
}
}
expect(config).toStrictEqual(expectedConfig)
})

it('test config values in production', () => {
jest.resetModules()
process.env.ENV = 'prod-green'
const { config } = require('../index')
const expectedConfig = {
env: 'prod-green',
appType: 'internal',
server: { port: '8050' },
geoserver: 'http://dummyuri',
views: { isCached: false },
analyticsAccount: 'replace_this',
googleVerification: 'replace_this',
fbAppId: 'replace_this',
httpTimeoutMs: '3000',
ordnanceSurvey: {
osGetCapabilitiesUrl: 'http://dummyuri',
osMapsUrl: 'http://dummyuri',
osNamesUrl: 'http://dummyuri',
osSearchKey: 'replace_this',
osMapsKey: 'replace_this',
osClientId: 'replace_this',
osClientSecret: 'replace_this'
},
siteUrl: 'http://dummyuri',
functionAppUrl: 'http://dummyuri',
ignoreUseAutomatedService: true,
placeApi: { url: 'http://dummyuri' },
agol: {
clientId: 'TEST_AGOL_CLIENT_ID',
clientSecret: 'TEST_AGOL_CLIENT_SECRET',
serviceId: 'DUMMY_SERVICE_ID',
serviceUrl: 'https://services1.arcgis.com/DUMMY_SERVICE_ID/arcgis/rest/services',
vectorTileUrl: 'https://tiles.arcgis.com/tiles/DUMMY_SERVICE_ID/arcgis/rest/services',
customerTeamEndPoint: '/Flood_Map_for_Planning_Query_Service/FeatureServer/0',
localAuthorityEndPoint: '/Flood_Map_for_Planning_Query_Service/FeatureServer/1',
isEnglandEndPoint: '/Flood_Map_for_Planning_Query_Service/FeatureServer/2',
floodZonesRiversAndSeaEndPoint: '/Flood_Zones_2_and_3_Rivers_and_Sea/FeatureServer/0',
riversAndSeaDefendedEndPoint: '/Rivers_and_Sea_Defended_Depth/FeatureServer',
riversAndSeaUndefendedEndPoint: '/Rivers_and_Sea_Undefended_Depth/FeatureServer',
riversAndSeaDefendedCCP1EndPoint: '/Rivers_and_Sea_Defended_Depth_CCP1/FeatureServer',
riversAndSeaUndefendedCCP1EndPoint: '/Rivers_and_Sea_Undefended_Depth_CCP1/FeatureServer',
surfaceWaterEndPoint: '/Risk_of_Flooding_from_Surface_Water_Depth_0mm/FeatureServer/0'
},
eamaps: {
serviceUrl: 'http://dummyEAMapslUrl',
@@ -51,8 +119,6 @@ describe('Ensure config is correct', () => {
tokenEndPoint: '/tokens/generateToken'
},
defraMap: {
agolServiceUrl: 'https://services1.arcgis.com/DUMMY_SERVICE_ID/arcgis/rest/services',
agolVectorTileUrl: 'https://tiles.arcgis.com/tiles/DUMMY_SERVICE_ID/arcgis/rest/services',
layerNameSuffix: '_NON_PRODUCTION'
},
riskAdminApi: {
37 changes: 33 additions & 4 deletions config/index.js
Original file line number Diff line number Diff line change
@@ -2,6 +2,30 @@ const { validateSchema } = require('./schema')
const { toBool } = require('./toBool')
require('./environment')

const agolEndpoints = {
customerTeamEndPoint: '/Flood_Map_for_Planning_Query_Service_NON_PRODUCTION/FeatureServer/0',
localAuthorityEndPoint: '/Flood_Map_for_Planning_Query_Service_NON_PRODUCTION/FeatureServer/1',
isEnglandEndPoint: '/Flood_Map_for_Planning_Query_Service_NON_PRODUCTION/FeatureServer/2',
floodZonesRiversAndSeaEndPoint: '/Flood_Zones_2_and_3_Rivers_and_Sea_NON_PRODUCTION/FeatureServer/0',
riversAndSeaDefendedEndPoint: '/Rivers_and_Sea_Defended_Depth_NON_PRODUCTION/FeatureServer',
riversAndSeaUndefendedEndPoint: '/Rivers_and_Sea_Undefended_Depth_NON_PRODUCTION/FeatureServer',
riversAndSeaDefendedCCP1EndPoint: '/Rivers_and_Sea_Defended_Depth_CCP1_NON_PRODUCTION/FeatureServer',
riversAndSeaUndefendedCCP1EndPoint: '/Rivers_and_Sea_Undefended_Depth_CCP1_NON_PRODUCTION/FeatureServer',
surfaceWaterEndPoint: '/Risk_of_Flooding_from_Surface_Water_Depth_0mm_NON_PRODUCTION/FeatureServer/0'
}

const isProduction = () => {
return process.env.ENV === 'prd' ||
process.env.ENV === 'production' ||
process.env.ENV === 'prod' ||
process.env.ENV === 'prod-green' ||
process.env.ENV === 'prod-blue'
}

const productioniseEndpoint = (endpoint) => {
return isProduction() ? endpoint.replace('_NON_PRODUCTION', '') : endpoint
}

const config = {
env: process.env.ENV,
appType: process.env.fmpAppType,
@@ -37,10 +61,15 @@ const config = {
serviceId: process.env.agolServiceId,
serviceUrl: `https://services1.arcgis.com/${process.env.agolServiceId}/arcgis/rest/services`,
vectorTileUrl: `https://tiles.arcgis.com/tiles/${process.env.agolServiceId}/arcgis/rest/services`,
customerTeamEndPoint: process.env.agolCustomerTeamEndPoint,
localAuthorityEndPoint: process.env.agolLocalAuthorityEndPoint,
isEnglandEndPoint: process.env.agolIsEnglandEndPoint,
floodZonesRiversAndSeaEndPoint: process.env.agolFloodZonesRiversAndSeaEndPoint
customerTeamEndPoint: productioniseEndpoint(agolEndpoints.customerTeamEndPoint),
localAuthorityEndPoint: productioniseEndpoint(agolEndpoints.localAuthorityEndPoint),
isEnglandEndPoint: productioniseEndpoint(agolEndpoints.isEnglandEndPoint),
floodZonesRiversAndSeaEndPoint: productioniseEndpoint(agolEndpoints.floodZonesRiversAndSeaEndPoint),
riversAndSeaDefendedEndPoint: productioniseEndpoint(agolEndpoints.riversAndSeaDefendedEndPoint),
riversAndSeaUndefendedEndPoint: productioniseEndpoint(agolEndpoints.riversAndSeaUndefendedEndPoint),
riversAndSeaDefendedCCP1EndPoint: productioniseEndpoint(agolEndpoints.riversAndSeaDefendedCCP1EndPoint),
riversAndSeaUndefendedCCP1EndPoint: productioniseEndpoint(agolEndpoints.riversAndSeaUndefendedCCP1EndPoint),
surfaceWaterEndPoint: productioniseEndpoint(agolEndpoints.surfaceWaterEndPoint)
},
eamaps: {
serviceUrl: process.env.eamapsServiceUrl,
7 changes: 6 additions & 1 deletion config/schema.js
Original file line number Diff line number Diff line change
@@ -45,7 +45,12 @@ const schema = Joi.object({
customerTeamEndPoint: Joi.string().required(),
localAuthorityEndPoint: Joi.string().required(),
isEnglandEndPoint: Joi.string().required(),
floodZonesRiversAndSeaEndPoint: Joi.string().required()
floodZonesRiversAndSeaEndPoint: Joi.string().required(),
riversAndSeaDefendedEndPoint: Joi.string().required(),
riversAndSeaUndefendedEndPoint: Joi.string().required(),
riversAndSeaDefendedCCP1EndPoint: Joi.string().required(),
riversAndSeaUndefendedCCP1EndPoint: Joi.string().required(),
surfaceWaterEndPoint: Joi.string().required()
},
eamaps: {
serviceUrl: Joi.string().uri().required(),
20 changes: 17 additions & 3 deletions server/__test-helpers__/server.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
const { getServer } = require('../../.jest/setup')
const constants = require('../constants')
const createServer = require('../../server')
let server

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

afterEach(async () => {
await server.stop()
})

const getServer = () => server

const submitGetRequest = async (options, header, expectedResponseCode = constants.statusCodes.OK) => {
options.method = 'GET'
@@ -13,7 +25,8 @@ const submitGetRequest = async (options, header, expectedResponseCode = constant

const submitPostRequest = async (options, expectedResponseCode = constants.statusCodes.REDIRECT) => {
options.method = 'POST'
return submitRequest(options, expectedResponseCode)
const response = await submitRequest(options, expectedResponseCode)
return response
}

const submitPostRequestExpectHandledError = async (options, errorMessage) => {
@@ -45,5 +58,6 @@ module.exports = {
submitGetRequest,
submitPostRequest,
submitPostRequestExpectHandledError,
submitPostRequestExpectServiceError
submitPostRequestExpectServiceError,
getServer
}
4 changes: 3 additions & 1 deletion server/index.js
Original file line number Diff line number Diff line change
@@ -28,9 +28,11 @@ async function createServer () {
]
})

// Cached server methods
await server.method(require('./services/pso-contact'))
await server.method(require('./services/pso-contact-by-polygon'))
await server.method(require('./services/flood-zones-by-polygon'))
await server.method(require('./services/floodDataByPolygon'))
await server.method(require('./services/floodZoneByPolygon'))
await server.method(require('./services/use-automated'))

// Register the plugins
21 changes: 11 additions & 10 deletions server/routes/__tests__/check-your-details.spec.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
const { getServer } = require('../../../.jest/setup')
const { assertCopy } = require('../../__test-helpers__/copy')
const {
submitGetRequest,
submitPostRequest
submitPostRequest,
getServer
} = require('../../__test-helpers__/server')
const { mockPolygons } = require('../../services/__tests__/__mocks__/floodZonesByPolygonMock')
const { mockPolygons } = require('../../services/__tests__/__mocks__/floodZoneByPolygonMock')
const { getCentreOfPolygon } = require('../../services/shape-utils')
jest.mock('../../services/agol/getContacts')
jest.mock('../../services/address')
jest.mock('@hapi/wreck')
const wreck = require('@hapi/wreck')
const user = {
fullName: 'John Smith',
email: '[email protected]'
}

const url = '/check-your-details'
let postSpy

describe('Check your details page', () => {
beforeEach(() => {
wreck.post.mockResolvedValue({
payload: {
applicationReferenceNumber: '12345',
nextTask: 'SEND_CONFIRMATION_EMAIL'
postSpy = jest.spyOn(wreck, 'post').mockImplementation(() => {
return {
payload: {
applicationReferenceNumber: '12345',
nextTask: 'SEND_CONFIRMATION_EMAIL'
}
}
})
})
@@ -123,7 +124,7 @@ describe('Check your details page', () => {
postcode: 'M1 1AA'
})

expect(wreck.post).toHaveBeenCalledWith('http://dummyuri/order-product-four', { json: true, payload: expectedPayload })
expect(postSpy).toHaveBeenCalledWith('http://dummyuri/order-product-four', { json: true, payload: expectedPayload })
}
})
})
2 changes: 1 addition & 1 deletion server/routes/__tests__/results.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { submitGetRequest } = require('../../__test-helpers__/server')
const { assertCopy } = require('../../__test-helpers__/copy')
const { mockPolygons } = require('../../services/__tests__/__mocks__/floodZonesByPolygonMock')
const { mockPolygons } = require('../../services/__tests__/__mocks__/floodDataByPolygonMock')
const { config } = require('../../../config')
jest.mock('../../services/agol/getContacts')

9 changes: 2 additions & 7 deletions server/routes/check-your-details.js
Original file line number Diff line number Diff line change
@@ -15,9 +15,6 @@ const getFunctionAppResponse = async (data) => {
return wreck.post(publishToQueueURL, { json: true, payload: JSON.stringify(payload) })
}

const floodZoneResultsToFloodZone = (floodZoneResults) =>
floodZoneResults.floodzone_3 ? '3' : floodZoneResults.floodzone_2 ? '2' : '1'

module.exports = [
{
method: 'GET',
@@ -26,8 +23,7 @@ module.exports = [
description: 'Application Review Summary',
handler: async (request, h) => {
const { polygon, fullName, recipientemail } = request.query
const floodZoneResults = await request.server.methods.getFloodZonesByPolygon(polygon)
const floodZone = floodZoneResultsToFloodZone(floodZoneResults)
const { floodZone } = await request.server.methods.getFloodZoneByPolygon(polygon)
const contactUrl = `/contact?polygon=${polygon}&fullName=${fullName}&recipientemail=${recipientemail}`
const confirmLocationUrl = `confirm-location?fullName=${fullName}&recipientemail=${recipientemail}`
return h.view('check-your-details', { polygon, fullName, recipientemail, contactUrl, confirmLocationUrl, floodZone })
@@ -43,8 +39,7 @@ module.exports = [
const payload = request.payload || {}
const { recipientemail, fullName, polygon } = payload
const coordinates = getCentreOfPolygon(polygon)
const floodZoneResults = await request.server.methods.getFloodZonesByPolygon(polygon)
const zoneNumber = floodZoneResultsToFloodZone(floodZoneResults)
const { floodZone: zoneNumber } = await request.server.methods.getFloodZoneByPolygon(polygon)
let applicationReferenceNumber

// Check if p4Request is duplicate
2 changes: 1 addition & 1 deletion server/routes/flood-zone-results.js
Original file line number Diff line number Diff line change
@@ -72,7 +72,7 @@ module.exports = [
if (!request.server.methods.ignoreUseAutomatedService()) {
useAutomatedService = contactDetails.useAutomatedService
}
const floodZoneResults = await request.server.methods.getFloodZonesByPolygon(polygon)
const floodZoneResults = await request.server.methods.getFloodDataByPolygon(polygon)

const plotSize = getAreaInHectares(polygon)
const floodZoneResultsData = new FloodRiskView.Model({
Loading