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

HOFF-160: Create postcode lookup component #466

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open

Conversation

mislam987
Copy link
Contributor

@mislam987 mislam987 commented Aug 12, 2024

What?

Create the postcode lookup component as a reusable solution, using the OS Places API - (HOFF-754, HOFF-768, HOFF-770, & HOFF-771)

  • Also includes a bug fix to allow punctuations in postcodes - HOFF-986

Why?

  • To replace the existing postcode lookup functionality across HOF forms
  • To have a configurable solution to enable customisations for each form
  • To enable users to enter a postcode and see a list of addresses to select from

How?

  • created new component folder /components/postcode-lookup including:
    • /templates folder with the postcode lookup HTML views
    • defaults.js file to include the default values used in the component
    • index.js file to handle the logic behind the postcode lookup (configuring fields, routing, OS Places API call, etc.). The values within this are set up dynamically to allow any form to customise the wording as required
  • added component reference to /components/index.js
  • added validations for fields in /controller/validation/validators.js
  • added functional test scenarios to /test/functional-tests/index.js
  • added mock steps configuration in /test/functional-tests/apps/postcode-lookup-default.js
  • added mock JSON data set to be used as a substitute for the actual API call in the functional tests to /test/data/postcode-lookup-data.json

Testing?

Tested the component on a service

Anything Else? (optional)

Check list

  • I have reviewed my own pull request for linting issues (e.g. adding new lines)
  • I have written tests (if relevant)
  • I have created a JIRA number for my branch
  • I have created a JIRA number for my commit
  • I have followed the chris beams method for my commit https://cbea.ms/git-commit/
    here is an example commit
  • Ensure drone builds are green especially tests
  • I will squash the commits before merging

* create postcode lookup component to replace existing lookups used in HOF forms:
   - use OS Places API to retrieve address data
   - make the component reusable and configurable by forms
Copy link
Contributor

@william-gu-hof william-gu-hof left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, functionality is good, just need some more consideration of code structure, readability, and some data structure checks / sanitisation


const defaults = require('./defaults');

const conditionalTranslate = (key, t) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use more meaningful variable name, think about the next dev looking at this code, what is t? what is the key for? Why does the logic need to compare the value in t indexed by key with the key itself?

Think about how you name your functions and variables, most of the time, if you named them well, no need for documentation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the variable name to something more suitable.

/* eslint-disable func-names */
'use strict';

const axios = require('axios');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't see axios included in package.json? How is this working?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added it back into package.json with the same version in master


postcodeValidation(value) {
// eslint-disable-next-line max-len
return Validators.regex(value, /^(([GIRgir] ?[ ]*0[ ]*[Aa]{2}[ ]*)|((([A-Za-z][ ]*[0-9]{1,2}[ ]*)|(([A-Za-z][ ]*[A-Ha-hJ-Yj-y][ ]*[0-9][ ]*[0-9]?)[ ]*|(([A-Za-z][ ]*[0-9][ ]*[A-Za-z][ ]*)|([A-Za-z][ ]*[A-Ha-hJ-Yj-y][ ]*[0-9]?[ ]*[A-Za-z][ ]*))))[-,. ]?[ ]*[0-9][ ]*[A-Za-z][ ]*[A-Za-z][ ]*))$/);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apart from the fact that the existing postcode validation rule allows for empty string, what are the other differences between the new one and the existing one? (looks like your regex is checking a lot more)

Just thinking about maintainability here of having 2 separate post code validation rules, not sure that is practical, depending on what the new regex is doing, maybe we can just overwrite the existing rule, and in your component, use the required and postcode validation together?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new validation also allows punctuation within the postcode, which I'm not sure if that is accepted in all postcode fields outside of this lookup. Would need reviewing to determine if this new postcode validation would suffice for all postcode inputs across our services.

package.json Outdated
@@ -1,7 +1,7 @@
{
"name": "hof",
"description": "A bootstrap for HOF projects",
"version": "20.5.4",
"version": "21.1.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a defined list of what each of the 3 part of the version number means? Is this a breaking change? Why adding a new component would be a breaking change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed this to be 21.2.0 since it's not a breaking change.

}
});

const getConfig = key => ({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not really a key, it is the value of the field name prefix, I would name this variable differently to avoid confusion

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed variable name.

assert.ok(url.includes('step=manual'));
}));

it('redirects to the lookup step on a successful postcode lookup', () => browser.url('/postcode-default-one')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once you managed to mock the request, we need to test on success lookup, the correct results are displayed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a unit test to cover this.

@@ -5,6 +5,14 @@ const Browser = require('./lib/browser');
const App = require('./lib/app');
const assert = require('assert');

// TO BE REVISITED FOR CREATING MOCK API CALL
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would also be good to write some unit tests after you refactor the index.js of the component with more functions, test them individually

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some unit tests for some of the functions in the component.

return super.saveValues(req, res, callback);
});
} else if (step === 'lookup') {
const addressResult = req.form.options.fields[`${addressKey}-select`].options.filter(obj => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should do some sanitisation of the input values gathered, strip out dodgy characters like < , {, ! and ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added logic to remove any instances of those characters

}).catch(error => {
if(error.response.status === '404' || error.response.status === '429' ||
error.response.status === '503' || error.response.status === '500') {
req.query.step === 'postcodeSearchIssue';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

too generic, are there detailed info on the API documentation on what the errors means?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added logger within the block of code where the function is called and got rid of the 'if' block from the code above to remove duplication. Also, modified the logic so that instead of checking for these specific error codes, it will now log the error regardless of the error code.

axios.get(apiURL + '?postcode=' + enteredPostcode + '&key=' + apiKey)
.then(function (response) {
const addressList = [];
_.forOwn(response.data.results, function (value) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do some checks on the response, make sure it is of the expected structure & type

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a check for the 'data' property in the response, but didn't check for any sub-properties of that because the component needs to still go to the address lookup page when there are no results returned for a given postcode.

Copy link
Contributor

@william-gu-hof william-gu-hof left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code is organised much better.

Just some small questions/suggestions that may help with code readability

@@ -0,0 +1,2 @@
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe add this folder to the .gitignore file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the folder to the .gitignore file

@@ -0,0 +1,31 @@
/* eslint max-len: 0, no-process-env: 0 */

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

either the naming of the file or the exported object structure can be improved. It looks like the file is just default error messages, so you can either rename the file to something like defaultErrorMessages.js or change the structure of the object returned to something like:

`module.exports = {
errorMessages: {
CANT_FIND: '...',
...;
}

}`

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've now moved the variables linked to an issue with the postcode lookup to within the POSTCODE_ERROR structure within this file. The rest of the properties are not issues with the lookup, so have kept them as independent variables.

@@ -30,6 +30,7 @@ const defaults = {
return convertPage(page);
}
},
deIndexForm: process.env.DEINDEX_FORM || 'false',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this needed for the work on postcode lookup?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accidentally left in from the de-indexing changes. Removed this now.

index.js Outdated
@@ -14,6 +14,7 @@ const router = require('./lib/router');
const health = require('./lib/health');
const serveStatic = require('./lib/serve-static');
const gaTagSetup = require('./lib/ga-tag');
const deIndexer = require('./lib/deindex');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similar to above, is this needed for the postcode lookup work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed this now.

@Rhodine-orleans-lindsay Rhodine-orleans-lindsay force-pushed the HOFF-768 branch 2 times, most recently from ab3906b to 34f4f76 Compare October 21, 2024 08:11
- amend postcode-lookup component to remove punctuation from postcode during api call to fix 400 error
- amend postcode-lookup component to remove punctuation from postcode in locals
- amend postcode-lookup component to remove punctuation from postcode in prepopulated manual fields
- amend postcode validation to allow all punctuation
- update yarn.lock
- remove unused vscode folder
Copy link
Contributor

@sulthan-ahmed sulthan-ahmed left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've just reviewed @Rhodine-orleans-lindsay change and that makes sense

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants