Skip to content

Commit 4798b5a

Browse files
authored
ENG-2360: improve PCLU postcode validation (#379)
* Update SB version * Connect up existing pattern to new prop * Update tests to reflect new validation * Fix tests again * Update postcode regex in accordance with HMRC * Tweak regex * SB update for Inputfield fix * SB update, test updates, error msg updates * Correct commenting * Update, uh Update form * More tests, whoops * Ensure postcodes in test meet validation * String regex, don't need case operator anymore * Workaround to trigger revalidation of postcode field on regex change * Tidyup * Update tests with new consistent field naming * Test updstes 2 * Centralise PCLU revalidation workarouhd * Variable-ise postcode selector * SB update for Inputfield fix * Avoid duplicating default PCLU regex, allow prop to fall back
1 parent 769ac7d commit 4798b5a

14 files changed

Lines changed: 110 additions & 83 deletions

File tree

cypress/integration/submit_spec.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,11 @@ describe('e2e test', () => {
7878
cy.get('#field-input--postcode').clear();
7979
cy.get('#postcode_button').click();
8080
cy.get('#field-error--postcode>span').should('contain','No postcode provided');
81-
// Removed to reflect way looser postcode checks added to the lookup for CWG
82-
// cy.get('#field-input--postcode').clear().type('s66%');
83-
// cy.get('#field-error--postcode>span').should('contain','Please enter a valid postcode');
81+
cy.get('#field-input--postcode').clear().type('s66%');
82+
cy.get('#field-error--postcode>span').should('contain','Please enter a valid UK postcode, using a space and capital letters');
8483
cy.get('#field-input--postcode').clear().type('s66');
85-
cy.get('#postcode_button').click();
86-
cy.get('#field-error--postcode>span').should('contain','Please enter a valid UK postcode to find your address');
87-
cy.get('#field-input--postcode').clear().type('hp2 6lq');
84+
cy.get('#field-error--postcode>span').should('contain','Please enter a valid UK postcode, using a space and capital letters');
85+
cy.get('#field-input--postcode').clear().type('HP2 6LQ');
8886
cy.get('#postcode_button').click();
8987
cy.get('#field-select--addressSelect').should('be.visible').select('112 ST. AGNELLS LANE')
9088
});

cypress/integration/update_spec.js

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ describe('e2e test typing transaction ID and choosing "yes" to claim gift aid on
2525
cy.get('#field-input--transactionId');
2626
cy.get('#field-input--firstname');
2727
cy.get('#field-input--lastname');
28-
cy.get('#field-input--emailaddress');
28+
cy.get('#field-input--email');
2929
cy.get('#field-input--postcode');
3030
cy.get('#postcode_button');
3131
cy.get('a[aria-describedby=field-error--addressDetails]');
@@ -86,27 +86,25 @@ describe('e2e test typing transaction ID and choosing "yes" to claim gift aid on
8686
});
8787

8888
it('email input field validation', () => {
89-
cy.get('#field-input--emailaddress').clear().type('test-@%comicrelief.com');
90-
cy.get('#field-error--emailaddress > span').should('contain','Please fill in a valid email address');
91-
cy.get('#field-input--emailaddress').clear().type('giftaid-staging@email.sls.comicrelief.com');
92-
cy.get('#field-error--emailaddress > span').should('not.exist')
89+
cy.get('#field-input--email').clear().type('test-@%comicrelief.com');
90+
cy.get('#field-error--email > span').should('contain','Please fill in a valid email address');
91+
cy.get('#field-input--email').clear().type('giftaid-staging@email.sls.comicrelief.com');
92+
cy.get('#field-error--email > span').should('not.exist')
9393
});
9494

9595
it('postcode field validation', () => {
9696
cy.get('#postcode_button').click();
9797
cy.get('#field-error--postcode>span').should('contain','No postcode provided');
98-
// Removed to reflect way looser postcode checks added to the lookup for CWG
99-
// cy.get('#field-input--postcode').clear().type('s66%');
100-
// cy.get('#field-error--postcode>span').should('contain','Please enter a valid postcode');
98+
cy.get('#field-input--postcode').clear().type('s66%');
99+
cy.get('#field-error--postcode>span').should('contain','Please enter a valid UK postcode, using a space and capital letters');
101100
cy.get('#field-input--postcode').clear().type('s66');
102-
cy.get('#postcode_button').click();
103-
cy.get('#field-error--postcode>span').should('contain','Please enter a valid UK postcode to find your address');
101+
cy.get('#field-error--postcode>span').should('contain','Please enter a valid UK postcode, using a space and capital letters');
104102
cy.get('#field-input--postcode').clear().type('se1 7tp');
105103
cy.get('button[type=submit]').click();
106104

107105
cy.get('#field-error--addressDetails > span').should('contain','Please fill in your address');
108106

109-
cy.get('#field-input--postcode').clear().type('hp2 6lq');
107+
cy.get('#field-input--postcode').clear().type('HP2 6LQ');
110108
cy.get('#postcode_button').click();
111109
cy.get('#field-select--addressSelect').should('be.visible').select('112 ST. AGNELLS LANE')
112110
});
@@ -140,7 +138,7 @@ describe('e2e test typing transaction ID and choosing "yes" to claim gift aid on
140138
});
141139

142140
it('clear email field', () => {
143-
cy.get('#field-input--emailaddress').clear()
141+
cy.get('#field-input--email').clear()
144142
});
145143

146144
it('verify success page', () => {
@@ -157,8 +155,8 @@ describe('e2e test typing transaction ID and choosing "No" to claim gift aid on
157155
cy.get('#field-input--transactionId').clear().type('2D487A59-716B-440D-BD43-50ED301DD9BA');
158156
cy.get('#field-input--firstname').clear().type(firstName);
159157
cy.get('#field-input--lastname').clear().type(lastName);
160-
cy.get('#field-input--emailaddress').clear().type('giftaid-staging@email.sls.comicrelief.com');
161-
cy.get('#field-input--postcode').clear().type('hp2 6lq');
158+
cy.get('#field-input--email').clear().type('giftaid-staging@email.sls.comicrelief.com');
159+
cy.get('#field-input--postcode').clear().type('HP2 6LQ');
162160
cy.get('#postcode_button').click();
163161
cy.get('#field-select--addressSelect').should('be.visible').select('112 ST. AGNELLS LANE');
164162
cy.get('input[type="radio"]').check('0').should('be.checked');
@@ -179,8 +177,8 @@ describe('Giftaid test when user comes from sms,online or call centre', () => {
179177
cy.get('input[type="radio"]').check('sms').should('be.checked');
180178
cy.get('#field-input--firstname').clear().type(firstName);
181179
cy.get('#field-input--lastname').clear().type(lastName);
182-
cy.get('#field-input--emailaddress').clear().type('giftaid-staging@email.sls.comicrelief.com');
183-
cy.get('#field-input--postcode').clear().type('hp2 6lq');
180+
cy.get('#field-input--email').clear().type('giftaid-staging@email.sls.comicrelief.com');
181+
cy.get('#field-input--postcode').clear().type('HP2 6LQ');
184182
cy.get('#postcode_button').click();
185183
cy.get('#field-select--addressSelect').should('be.visible').select('112 ST. AGNELLS LANE');
186184
cy.get('input[type="radio"]').check('1').should('be.checked');
@@ -198,8 +196,8 @@ describe('Giftaid test when user comes from sms,online or call centre', () => {
198196
cy.get('input[type="radio"]').check('online').should('be.checked');
199197
cy.get('#field-input--firstname').clear().type(firstName);
200198
cy.get('#field-input--lastname').clear().type(lastName);
201-
cy.get('#field-input--emailaddress').clear().type('giftaid-staging@email.sls.comicrelief.com');
202-
cy.get('#field-input--postcode').clear().type('hp2 6lq');
199+
cy.get('#field-input--email').clear().type('giftaid-staging@email.sls.comicrelief.com');
200+
cy.get('#field-input--postcode').clear().type('HP2 6LQ');
203201
cy.get('#postcode_button').click();
204202
cy.get('#field-select--addressSelect').should('be.visible').select('112 ST. AGNELLS LANE');
205203
cy.get('input[type="radio"]').check('1').should('be.checked');
@@ -218,8 +216,8 @@ describe('Giftaid test when user comes from sms,online or call centre', () => {
218216
cy.get('#field-input--transactionId').clear().type('5c6a9920355f6');
219217
cy.get('#field-input--firstname').clear().type(firstName);
220218
cy.get('#field-input--lastname').clear().type(lastName);
221-
cy.get('#field-input--emailaddress').clear().type('giftaid-staging@email.sls.comicrelief.com');
222-
cy.get('#field-input--postcode').clear().type('hp2 6lq');
219+
cy.get('#field-input--email').clear().type('giftaid-staging@email.sls.comicrelief.com');
220+
cy.get('#field-input--postcode').clear().type('HP2 6LQ');
223221
cy.get('#postcode_button').click();
224222
cy.get('#field-select--addressSelect').should('be.visible').select('112 ST. AGNELLS LANE');
225223
cy.get('input[type="radio"]').check('1').should('be.checked');
@@ -264,7 +262,7 @@ describe('Ensure redirect functionality from Success page', () => {
264262
.get('#field-input--transactionId').should('have.value', "")
265263
.get('#field-input--firstname').should('have.value', "")
266264
.get('#field-input--lastname').should('have.value', "")
267-
.get('#field-input--emailaddress').should('have.value', "")
265+
.get('#field-input--email').should('have.value', "")
268266
.get('#field-input--postcode').should('have.value', "")
269267
});
270268
});
@@ -278,8 +276,8 @@ describe('Ensure url validation if string is less than 5 characters', () => {
278276
cy.get('input[type="radio"]').check('online').should('be.checked');
279277
cy.get('#field-input--firstname').clear().type(firstName);
280278
cy.get('#field-input--lastname').clear().type(lastName);
281-
cy.get('#field-input--emailaddress').clear().type('giftaid-staging@email.sls.comicrelief.com');
282-
cy.get('#field-input--postcode').clear().type('hp2 6lq');
279+
cy.get('#field-input--email').clear().type('giftaid-staging@email.sls.comicrelief.com');
280+
cy.get('#field-input--postcode').clear().type('HP2 6LQ');
283281
cy.get('#postcode_button').click();
284282
cy.get('#field-select--addressSelect').should('be.visible').select('112 ST. AGNELLS LANE');
285283
cy.get('input[type="radio"]').check(giftAidChecked).should('be.checked');

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"dependencies": {
66
"@babel/polyfill": "^7.11.5",
77
"@comicrelief/pattern-lab": "7.58.6",
8-
"@comicrelief/storybook": "1.31.0",
8+
"@comicrelief/storybook": "1.33.3",
99
"@snyk/protect": "^1.986.0",
1010
"autoprefixer": "10.0.0",
1111
"axios": "^0.21.1",

src/pages/GiftAid/GiftAid.js

Lines changed: 62 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@ import {
1919
scrollToError,
2020
getPathParams,
2121
hiddenFields,
22-
postCodePattern,
22+
GBPostCodePattern,
23+
OverseasPostCodePattern,
2324
justInTimeLinkText,
2425
validateForm,
2526
getFieldValidations,
26-
initialValidity,
27+
initialFormValidity,
2728
getRoute,
2829
} from './utils/Utils';
2930

@@ -36,9 +37,14 @@ function GiftAid(props) {
3637
const update = props.location.pathname.includes("update"); // initialise updating param state
3738
const [updating, setUpdating] = useState(update); // set to true if path contains the string update
3839
const [pathParams, setPathParams] = useState({}); // initialise submit path param state
39-
const [formValidityState, setFormValidityState] = useState(initialValidity); // intitialise form validity states
40+
const [formValidityState, setFormValidityState] = useState(initialFormValidity); // intitialise form validity states
4041
const [fieldValidation, setFieldValidation] = useState(getFieldValidations(update)); // intitialise field validation state based on form type
4142
const [isSubmitting, setIsSubmitting] = useState(false);
43+
// As GB is the default country, set the matching postcode regex pattern as default too
44+
const [currentPostcodePattern, setCurrentPostcodePattern] = useState(GBPostCodePattern);
45+
46+
// Simple counter to allow us to trigger the child 'revalidate postcode' function after regex updates
47+
const [postcodeRevalidate, setPostcodeRevalidate] = useState(0);
4248

4349
const inputRef = useRef(null);
4450

@@ -64,7 +70,7 @@ function GiftAid(props) {
6470
return () => {
6571
// GiftAid component unmounts
6672
// reset states
67-
setFormValidityState(initialValidity);
73+
setFormValidityState(initialFormValidity);
6874
setFieldValidation({});
6975
setUpdating(false);
7076
setUrlTransactionId(null);
@@ -73,6 +79,28 @@ function GiftAid(props) {
7379
}
7480
}, []);
7581

82+
/**
83+
* Crummy workaround to trigger a revalidation
84+
* as the bespoke validation here has issues
85+
*/
86+
const revalidatePostcode = () => {
87+
// Store the current postcode to re-add
88+
const postcodeField = document.getElementById("field-input--postcode");
89+
const currentPostcodeValue = postcodeField.value;
90+
const blurEvent = new Event('blur', { bubbles: true });
91+
92+
// Temporarily reset the postcode field and programmatically
93+
// trigger a blur event to make the validation take notice
94+
postcodeField.value = '';
95+
postcodeField.dispatchEvent(blurEvent);
96+
97+
setTimeout(() => {
98+
// Immediately re-add the value and trigger another blur event
99+
postcodeField.value = currentPostcodeValue;
100+
postcodeField.dispatchEvent(blurEvent);
101+
}, 1);
102+
};
103+
76104

77105
/**
78106
* Fetches decrypted MSISDN using token
@@ -108,34 +136,37 @@ function GiftAid(props) {
108136

109137
/**
110138
* Updates validation state for form fields
111-
* @param childState
112-
* @param name
139+
* @param thisFieldsState
140+
* @param thisFieldsName
113141
*/
114-
const setFieldValidity = (childState, name) => {
115-
const prevStateField = fieldValidation[name];
116-
const fieldUndefined = prevStateField === undefined;
117-
const valueUndefined = typeof prevStateField !== 'undefined' && prevStateField.value === undefined;
118-
const newValue = typeof prevStateField !== 'undefined' && prevStateField.value !== childState.value;
119-
const newState = (fieldUndefined === false && newValue) || (valueUndefined === true || newValue);
120-
142+
const setFieldValidity = (thisFieldsState, thisFieldsName) => {
143+
const thisFieldsPreviousState = fieldValidation[thisFieldsName];
144+
const isFieldUndefined = thisFieldsPreviousState === undefined;
145+
const isFieldValueUndefined = typeof thisFieldsPreviousState !== 'undefined' && thisFieldsPreviousState.value === undefined;
146+
const isNewFieldValue = typeof thisFieldsPreviousState !== 'undefined' && thisFieldsPreviousState.value !== thisFieldsState.value;
147+
const isUpdatedState = (isFieldUndefined === false && isNewFieldValue) || (isFieldValueUndefined === true || isNewFieldValue);
148+
121149
// set field validation for marketing consent fields if present
122-
const marketingConsentFieldsChanged = fieldUndefined === false &&
123-
(childState.fieldValidation !== prevStateField.fieldValidation);
150+
const marketingConsentFieldsChanged = isFieldUndefined === false &&
151+
(thisFieldsState.fieldValidation !== thisFieldsPreviousState.fieldValidation);
152+
153+
if ((thisFieldsPreviousState && isUpdatedState) || marketingConsentFieldsChanged === true) {
154+
155+
// Update postcode regex is 'Country' select value has changed
156+
if (thisFieldsName === 'country' && thisFieldsState.value !== thisFieldsPreviousState.value){
157+
158+
// Ignore the on-mount validation call
159+
if (thisFieldsPreviousState.value !== undefined) {
160+
// Switch regex patterns accordingly; if a non-GB value, this undefined value
161+
// will cause the PCLU to fallback to its default, much looser regex
162+
setCurrentPostcodePattern(thisFieldsState.value === 'GB' ? GBPostCodePattern : undefined);
163+
// Call our workaround to trigger a revalidation of the PCLU postcode field
164+
revalidatePostcode();
165+
}
166+
}
124167

125-
if ((prevStateField && newState) || marketingConsentFieldsChanged === true) {
126-
if (name === 'emailaddress' && childState.value === '') { // make email field optional
127-
setFieldValidation({
128-
...fieldValidation,
129-
emailaddress: {
130-
valid: true,
131-
value: childState.value,
132-
message: childState.message,
133-
showErrorMessage: false,
134-
},
135-
});
136-
} else {
137168
// Reset url transaction Id state
138-
if (name === 'transactionId' && childState.valid) {
169+
if (thisFieldsName === 'transactionId' && thisFieldsState.valid) {
139170
setFormValidityState({
140171
...formValidityState,
141172
urlTransactionId: {
@@ -144,13 +175,12 @@ function GiftAid(props) {
144175
}
145176
});
146177
}
147-
fieldValidation[name] = childState;
178+
fieldValidation[thisFieldsName] = thisFieldsState;
148179
setFieldValidation({...fieldValidation});
149180

150181
return {
151182
...fieldValidation,
152183
};
153-
}
154184
}
155185
};
156186

@@ -196,7 +226,7 @@ function GiftAid(props) {
196226
const contextProps = {
197227
urlTransactionId,
198228
hiddenFields,
199-
postCodePattern,
229+
currentPostcodePattern,
200230
justInTimeLinkText,
201231
formValidityState,
202232
fieldValidation,
@@ -219,6 +249,7 @@ function GiftAid(props) {
219249
<SubmitForm
220250
title="Submit Form"
221251
msisdn={msisdn}
252+
postcodeRevalidate={postcodeRevalidate}
222253
/>
223254
)}
224255
</FormProvider>

src/pages/GiftAid/SubmitForm/SubmitForm.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ function SubmitForm(props) {
3434
const {
3535
refs,
3636
setFieldValidity,
37-
postCodePattern,
37+
currentPostcodePattern,
3838
justInTimeLinkText,
3939
formValidityState,
4040
fieldValidation,
@@ -47,7 +47,6 @@ function SubmitForm(props) {
4747

4848
// Declare state variables
4949
const [inputFieldProps, setInputFieldProps] = useState([]); // initialise form inputFieldProps state
50-
5150
const marketingProps = {};
5251

5352
// Set additional props for MarketingConsent based on site
@@ -88,7 +87,6 @@ function SubmitForm(props) {
8887
setInputFieldProps(mergeInputFieldProps(submitFormFields, props));
8988
};
9089

91-
9290
return (
9391

9492
<Form className="giftaid__form" >
@@ -101,7 +99,8 @@ function SubmitForm(props) {
10199
ref={refs}
102100
label="Home address"
103101
showErrorMessages={formValidityState.showErrorMessages}
104-
pattern={postCodePattern}
102+
postcodePattern={currentPostcodePattern}
103+
invalidErrorText="Please enter a valid UK postcode, using a space and capital letters"
105104
isAddressValid={
106105
(validation) => {
107106
Object.keys(validation).map(key => setFieldValidity(validation[key], key));

src/pages/GiftAid/SubmitForm/marketingConsentData.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const marketingConsentData = {
2222
],
2323
field: [
2424
{
25-
id: 'emailAddress',
25+
id: 'email',
2626
type: 'email',
2727
name: 'email',
2828
label: 'Email address',

src/pages/GiftAid/UpdateForm/UpdateForm.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ function UpdateForm(props) {
2525
const {
2626
refs,
2727
setFieldValidity,
28-
postCodePattern,
28+
currentPostcodePattern,
2929
justInTimeLinkText,
3030
formValidityState,
3131
fieldValidation,
@@ -83,7 +83,8 @@ function UpdateForm(props) {
8383
ref={refs}
8484
label="Home address"
8585
showErrorMessages={formValidityState.showErrorMessages}
86-
pattern={postCodePattern}
86+
postcodePattern={currentPostcodePattern}
87+
invalidErrorText="Please enter a valid UK postcode, using a space and capital letters"
8788
isAddressValid={
8889
(validation) => {
8990
Object.keys(validation).map(key => setFieldValidity(validation[key], key));

src/pages/GiftAid/UpdateForm/UpdateFormFields.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ export const updateFormFields = {
8484
invalidErrorText: 'This field only accepts alphanumeric characters and , . ( ) / & \' - ',
8585
pattern: '^[A-Za-z0-9]+[ \\- ,.()\\/&\\\'\\w]+$'
8686
},
87-
emailAddress: {
88-
id: 'emailaddress',
87+
email: {
88+
id: 'email',
8989
type: 'email',
9090
name: 'email',
9191
label: 'Email address',

0 commit comments

Comments
 (0)