Skip to content

Commit

Permalink
feat(core): Improve error messages for invalid custom field inputs
Browse files Browse the repository at this point in the history
Relates to #85
  • Loading branch information
michaelbromley committed Jul 16, 2019
1 parent 8f763b2 commit af13dc2
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 21 deletions.
12 changes: 6 additions & 6 deletions packages/core/e2e/custom-fields.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ describe('Custom fields', () => {
}
}
`);
}, `The custom field value ['hello'] does not match the pattern [^[0-9][a-z]+$]`),
}, `The custom field 'validateString' value ['hello'] does not match the pattern [^[0-9][a-z]+$]`),
);

it(
Expand All @@ -234,7 +234,7 @@ describe('Custom fields', () => {
}
}
`);
}, `The custom field value ['tiny'] is invalid. Valid options are ['small', 'medium', 'large']`),
}, `The custom field 'stringWithOptions' value ['tiny'] is invalid. Valid options are ['small', 'medium', 'large']`),
);

it('valid string option', async () => {
Expand Down Expand Up @@ -272,7 +272,7 @@ describe('Custom fields', () => {
}
}
`);
}, `The custom field value ['servus'] does not match the pattern [^[0-9][a-z]+$]`),
}, `The custom field 'validateLocaleString' value ['servus'] does not match the pattern [^[0-9][a-z]+$]`),
);

it(
Expand All @@ -285,7 +285,7 @@ describe('Custom fields', () => {
}
}
`);
}, `The custom field value [12] is greater than the maximum [10]`),
}, `The custom field 'validateInt' value [12] is greater than the maximum [10]`),
);

it(
Expand All @@ -298,7 +298,7 @@ describe('Custom fields', () => {
}
}
`);
}, `The custom field value [10.6] is greater than the maximum [10.5]`),
}, `The custom field 'validateFloat' value [10.6] is greater than the maximum [10.5]`),
);

it(
Expand All @@ -316,7 +316,7 @@ describe('Custom fields', () => {
}
}
`);
}, `The custom field value [2019-01-01T05:25:00.000Z] is less than the minimum [2019-01-01T08:30]`),
}, `The custom field 'validateDateTime' value [2019-01-01T05:25:00.000Z] is less than the minimum [2019-01-01T08:30]`),
);

it(
Expand Down
43 changes: 34 additions & 9 deletions packages/core/src/api/common/validate-custom-field-value.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ import {
* Validates the value of a custom field input against any configured constraints.
* If validation fails, an error is thrown.
*/
export function validateCustomFieldValue(config: CustomFieldConfig, value: any, languageCode?: LanguageCode): void {
export function validateCustomFieldValue(
config: CustomFieldConfig,
value: any,
languageCode?: LanguageCode,
): void {
switch (config.type) {
case 'string':
case 'localeString':
Expand All @@ -38,32 +42,45 @@ export function validateCustomFieldValue(config: CustomFieldConfig, value: any,
validateCustomFunction(config, value, languageCode);
}

function validateCustomFunction<T extends TypedCustomFieldConfig<any, any>>(config: T, value: any, languageCode?: LanguageCode) {
function validateCustomFunction<T extends TypedCustomFieldConfig<any, any>>(
config: T,
value: any,
languageCode?: LanguageCode,
) {
if (typeof config.validate === 'function') {
const error = config.validate(value);
if (typeof error === 'string') {
throw new UserInputError(error);
}
if (Array.isArray(error)) {
const localizedError = error.find(e => e.languageCode === (languageCode || DEFAULT_LANGUAGE_CODE)) || error[0];
const localizedError =
error.find(e => e.languageCode === (languageCode || DEFAULT_LANGUAGE_CODE)) || error[0];
throw new UserInputError(localizedError.value);
}
}
}

function validateStringField(config: StringCustomFieldConfig | LocaleStringCustomFieldConfig, value: string): void {
function validateStringField(
config: StringCustomFieldConfig | LocaleStringCustomFieldConfig,
value: string,
): void {
const { pattern } = config;
if (pattern) {
const re = new RegExp(pattern);
if (!re.test(value)) {
throw new UserInputError('error.field-invalid-string-pattern', { value, pattern });
throw new UserInputError('error.field-invalid-string-pattern', {
name: config.name,
value,
pattern,
});
}
}
const options = (config as StringCustomFieldConfig).options;
if (options) {
const validOptions = options.map(o => o.value);
if (!validOptions.includes(value)) {
throw new UserInputError('error.field-invalid-string-option', {
name: config.name,
value,
validOptions: validOptions.map(o => `'${o}'`).join(', '),
});
Expand All @@ -74,19 +91,27 @@ function validateStringField(config: StringCustomFieldConfig | LocaleStringCusto
function validateNumberField(config: IntCustomFieldConfig | FloatCustomFieldConfig, value: number): void {
const { min, max } = config;
if (min != null && value < min) {
throw new UserInputError('error.field-invalid-number-range-min', { value, min });
throw new UserInputError('error.field-invalid-number-range-min', { name: config.name, value, min });
}
if (max != null && max < value) {
throw new UserInputError('error.field-invalid-number-range-max', { value, max });
throw new UserInputError('error.field-invalid-number-range-max', { name: config.name, value, max });
}
}
function validateDateTimeField(config: DateTimeCustomFieldConfig, value: string): void {
const { min, max } = config;
const valueDate = new Date(value);
if (min != null && valueDate < new Date(min)) {
throw new UserInputError('error.field-invalid-datetime-range-min', { value: valueDate.toISOString(), min });
throw new UserInputError('error.field-invalid-datetime-range-min', {
name: config.name,
value: valueDate.toISOString(),
min,
});
}
if (max != null && new Date(max) < valueDate) {
throw new UserInputError('error.field-invalid-datetime-range-max', { value: valueDate.toISOString(), max });
throw new UserInputError('error.field-invalid-datetime-range-max', {
name: config.name,
value: valueDate.toISOString(),
max,
});
}
}
12 changes: 6 additions & 6 deletions packages/core/src/i18n/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@
"email-address-not-verified": "Please verify this email address before logging in",
"entity-has-no-translation-in-language": "Translatable entity '{ entityName }' has not been translated into the requested language ({ languageCode })",
"entity-with-id-not-found": "No { entityName } with the id '{ id }' could be found",
"field-invalid-datetime-range-max": "The custom field value [{ value }] is greater than the maximum [{ max }]",
"field-invalid-datetime-range-min": "The custom field value [{ value }] is less than the minimum [{ min }]",
"field-invalid-number-range-max": "The custom field value [{ value }] is greater than the maximum [{ max }]",
"field-invalid-number-range-min": "The custom field value [{ value }] is less than the minimum [{ min }]",
"field-invalid-string-option": "The custom field value ['{ value }'] is invalid. Valid options are [{ validOptions }]",
"field-invalid-string-pattern": "The custom field value ['{ value }'] does not match the pattern [{ pattern }]",
"field-invalid-datetime-range-max": "The custom field '{ name }' value [{ value }] is greater than the maximum [{ max }]",
"field-invalid-datetime-range-min": "The custom field '{ name }' value [{ value }] is less than the minimum [{ min }]",
"field-invalid-number-range-max": "The custom field '{ name }' value [{ value }] is greater than the maximum [{ max }]",
"field-invalid-number-range-min": "The custom field '{ name }' value [{ value }] is less than the minimum [{ min }]",
"field-invalid-string-option": "The custom field '{ name }' value ['{ value }'] is invalid. Valid options are [{ validOptions }]",
"field-invalid-string-pattern": "The custom field '{ name }' value ['{ value }'] does not match the pattern [{ pattern }]",
"forbidden": "You are not currently authorized to perform this action",
"identifier-change-token-not-recognized": "Identifier change token not recognized",
"identifier-change-token-has-expired": "Identifier change token has expired",
Expand Down

0 comments on commit af13dc2

Please sign in to comment.