Skip to content

Commit

Permalink
Merge pull request #553 from open-formulieren/of-task/3383-phone-numb…
Browse files Browse the repository at this point in the history
…er-validation

 [OF#3383] Refactor phone number validation
  • Loading branch information
sergei-maertens authored Sep 29, 2023
2 parents 5db3465 + 25599dd commit 1f64a86
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 39 deletions.
63 changes: 24 additions & 39 deletions src/formio/validators/plugins.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,30 @@
import {post} from '../../api';

const errorMessageMap = {
'kvk-kvkNumber': 'Invalid Kvk Number',
'kvk-rsin': 'Invalid RSIN',
'kvk-branchNumber': 'Invalid Branch Number',
'phonenumber-international': 'Invalid international phonenumber',
'phonenumber-nl': 'Invalid Dutch phonenumber',
};
export const pluginsAPIValidator = {
key: `validate.backendApi`,
check(component, setting, value) {
if (!value) return true;

const pluginAPIValidator = plugin => {
let defaultMsg = errorMessageMap[plugin];
// catches undefined too
if (defaultMsg == null) {
defaultMsg = 'Invalid';
}
const plugins = component.component.validate.plugins;
const {baseUrl} = component.currentForm?.options || component.options;

return {
key: `validate.${plugin}`,
message(component) {
return component.t(component.errorMessage(defaultMsg), {
field: component.errorLabel,
data: component.data,
const promises = plugins.map(plugin => {
const url = `${baseUrl}validation/plugins/${plugin}`;
return post(url, {value}).then(response => {
const valid = response.data.isValid;
return valid ? true : response.data.messages.join('<br>');
});
},
check(component, setting, value) {
if (!value) return true;
});
return Promise.all(promises)
.then(results => {
const anyValid = results.some(result => result === true);

const {baseUrl} = component.currentForm?.options || component.options;
const url = `${baseUrl}validation/plugins/${plugin}`;
return post(url, {value})
.then(response => {
const valid = response.data.isValid;
return valid ? true : response.data.messages.join('<br>');
})
.catch(() => false);
},
};
if (anyValid) return true;

return results.join('<br>');
})
.catch(() => false);
},
};

/**
Expand All @@ -46,13 +35,9 @@ const pluginAPIValidator = plugin => {
*/
const enableValidationPlugins = component => {
if (Array.isArray(component.component.validate.plugins)) {
for (let plugin of component.component.validate.plugins) {
const validator = pluginAPIValidator(plugin);
if (validator == null) continue;
component.component.validateOn = 'blur';
component.validator.validators[plugin] = validator;
component.validators.push(plugin);
}
component.component.validateOn = 'blur';
component.validator.validators.backendApi = pluginsAPIValidator;
component.validators.push('backendApi');
}
};

Expand Down
15 changes: 15 additions & 0 deletions src/jstests/formio/components/fixtures/phonenumber.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const phoneNumberComponent = {
label: 'Phone Number',
key: 'phonenumber',
type: 'phoneNumber',
input: true,
validate: {
backendApi: true,
plugins: ['phonenumber-international', 'phonenumber-nl'],
},
};

const validSamples = ['0630123456', '+31630123456'];
const inValidSamples = ['63012345', '+3163012345'];

export {phoneNumberComponent, validSamples, inValidSamples};
36 changes: 36 additions & 0 deletions src/jstests/formio/validators/mocks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {rest} from 'msw';

import {BASE_URL} from 'api-mocks';

const INTERNATIONAL_VALIDATION_ENDPOINT = `${BASE_URL}validation/plugins/phonenumber-international`;
const DUTCH_VALIDATION_ENDPOINT = `${BASE_URL}validation/plugins/phonenumber-nl`;

export const phoneNumberValidations = {
mockValidInternationalPhonenumberPost: rest.post(
INTERNATIONAL_VALIDATION_ENDPOINT,
async (req, res, ctx) => {
return res(ctx.status(200), ctx.json({isValid: true, messages: []}));
}
),

mockInValidInternationalPhonenumberPost: rest.post(
INTERNATIONAL_VALIDATION_ENDPOINT,
async (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({isValid: false, messages: ['Invalid international phone number']})
);
}
),

mockValidDutchPhonenumberPost: rest.post(DUTCH_VALIDATION_ENDPOINT, async (req, res, ctx) => {
return res(ctx.status(200), ctx.json({isValid: true, messages: []}));
}),

mockInValidDutchPhonenumberPost: rest.post(DUTCH_VALIDATION_ENDPOINT, async (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({isValid: false, messages: ['Invalid dutch phone number']})
);
}),
};
68 changes: 68 additions & 0 deletions src/jstests/formio/validators/pluginapivalidator.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import {
inValidSamples,
phoneNumberComponent,
validSamples,
} from 'jstests/formio/components/fixtures/phonenumber';

import {BASE_URL} from 'api-mocks';
import mswServer from 'api-mocks/msw-server';
import {pluginsAPIValidator} from 'formio/validators/plugins';

import {phoneNumberValidations} from './mocks';

describe('The OpenForms plugins validation', () => {
test('tests expected errors are returned when phone number is invalid', async () => {
mswServer.use(
phoneNumberValidations.mockInValidDutchPhonenumberPost,
phoneNumberValidations.mockInValidInternationalPhonenumberPost
);

const component = {
component: phoneNumberComponent,
options: {
baseUrl: BASE_URL,
},
};

for (const sample of inValidSamples) {
const result = await pluginsAPIValidator.check(component, undefined, sample);
expect(result).toBe('Invalid international phone number<br>Invalid dutch phone number');
}
});

test('tests no errors are returned when phone number is valid', async () => {
mswServer.use(
phoneNumberValidations.mockValidDutchPhonenumberPost,
phoneNumberValidations.mockValidInternationalPhonenumberPost
);

const component = {
component: phoneNumberComponent,
options: {
baseUrl: BASE_URL,
},
};

for (const sample of validSamples) {
const result = await pluginsAPIValidator.check(component, undefined, sample);
expect(result).toBe(true);
}
});

test('tests no errors are returned when phone number is null', async () => {
mswServer.use(
phoneNumberValidations.mockValidDutchPhonenumberPost,
phoneNumberValidations.mockValidInternationalPhonenumberPost
);

const component = {
component: phoneNumberComponent,
options: {
baseUrl: BASE_URL,
},
};

const result = await pluginsAPIValidator.check(component, undefined, null);
expect(result).toBe(true);
});
});

0 comments on commit 1f64a86

Please sign in to comment.