diff --git a/packages/core/admin/admin/src/content-manager/components/EditViewDataManagerProvider/utils/schema.js b/packages/core/admin/admin/src/content-manager/components/EditViewDataManagerProvider/utils/schema.js index 613c492ce0..52e516880f 100644 --- a/packages/core/admin/admin/src/content-manager/components/EditViewDataManagerProvider/utils/schema.js +++ b/packages/core/admin/admin/src/content-manager/components/EditViewDataManagerProvider/utils/schema.js @@ -338,7 +338,10 @@ const createYupSchemaAttribute = (type, validations, options) => { break; } case 'regex': - schema = schema.matches(new RegExp(validationValue), errorsTrads.regex); + schema = schema.matches(new RegExp(validationValue), { + message: errorsTrads.regex, + excludeEmptyString: !validations.required, + }); break; case 'lowercase': if (['text', 'textarea', 'email', 'string'].includes(type)) { diff --git a/packages/core/strapi/lib/services/entity-validator/__tests__/validators.test.js b/packages/core/strapi/lib/services/entity-validator/__tests__/validators.test.js index e772f4e19f..73c7ee84f1 100644 --- a/packages/core/strapi/lib/services/entity-validator/__tests__/validators.test.js +++ b/packages/core/strapi/lib/services/entity-validator/__tests__/validators.test.js @@ -20,6 +20,102 @@ describe('Entity validator', () => { fakeFindOne.mockReset(); }); + describe('String RegExp validator', () => { + const fakeModel = { + kind: 'contentType', + modelName: 'test-model', + uid: 'test-uid', + privateAttributes: [], + options: {}, + attributes: { + attrStringRequiredRegex: { type: 'string', required: true }, + attrStringNotRequiredRegex: { type: 'string', required: false }, + }, + }; + + test('It fails the validation of an empty string for a required field', () => { + const validator = strapiUtils.validateYupSchema( + entityValidator.string( + { + attr: { type: 'string', required: true, regex: '^\\d+$' }, + model: fakeModel, + updatedAttribute: { + name: 'attrStringRequiredRegex', + value: '', + }, + entity: null, + }, + { isDraft: false } + ) + ); + + return expect(validator('')).rejects.toBeInstanceOf(YupValidationError); + }); + + test('It validates successfully for a string that follows regex for a required field', () => { + const value = '1234'; + + const validator = strapiUtils.validateYupSchema( + entityValidator.string( + { + attr: { type: 'string', required: true, regex: '^\\d+$' }, + model: fakeModel, + updatedAttribute: { + name: 'attrStringRequiredRegex', + value, + }, + entity: null, + }, + { isDraft: false } + ) + ); + + return expect(validator(value)).resolves.toEqual(value); + }); + + test('It validates empty string successfully for non-required field with regex constraint', () => { + const value = ''; + + const validator = strapiUtils.validateYupSchema( + entityValidator.string( + { + attr: { type: 'string', required: false, regex: '^\\d+$' }, + model: fakeModel, + updatedAttribute: { + name: 'attrStringNotRequiredRegex', + value, + }, + entity: null, + }, + { isDraft: false } + ) + ); + + return expect(validator(value)).resolves.toEqual(value); + }); + + test('It validates successfully for string that follows regex for a non-required field', () => { + const value = '1234'; + + const validator = strapiUtils.validateYupSchema( + entityValidator.string( + { + attr: { type: 'string', required: false, regex: '^\\d+$' }, + model: fakeModel, + updatedAttribute: { + name: 'attrStringNotRequiredRegex', + value, + }, + entity: null, + }, + { isDraft: false } + ) + ); + + return expect(validator(value)).resolves.toEqual(value); + }); + }); + describe('String unique validator', () => { const fakeModel = { kind: 'contentType', diff --git a/packages/core/strapi/lib/services/entity-validator/validators.js b/packages/core/strapi/lib/services/entity-validator/validators.js index ac3c117c15..f623da7dae 100644 --- a/packages/core/strapi/lib/services/entity-validator/validators.js +++ b/packages/core/strapi/lib/services/entity-validator/validators.js @@ -104,7 +104,9 @@ const addMaxFloatValidator = (validator, { attr }) => * @returns {StringSchema} */ const addStringRegexValidator = (validator, { attr }) => - _.isUndefined(attr.regex) ? validator : validator.matches(new RegExp(attr.regex)); + _.isUndefined(attr.regex) + ? validator + : validator.matches(new RegExp(attr.regex), { excludeEmptyString: !attr.required }); /** *