Repository: jhipster/generator-jhipster (ts)

Issue:
Java code with enums with custom values don't compile
##### **Overview of the issue** & **reproduction**

When importing such a JDL content:
```
entity MyEntity {
  myField MyEnum
}

enum MyEnum {
  AAA(aaa),
  BBB(bbb)
}
```

The Java code won't accept the custom values because they are generated (didn't seem so before, but anyway...).

##### **Motivation for or Use Case**

Generated code should compile.

##### **Reproduce the error**

Generate an app with
```
application
  config {
    baseName testWithEnums
  }}

entity MyEntity {
  myField MyEnum
}

enum MyEnum {
  AAA(aaa),
  BBB(bbb)
}
```

Check the generated enum, you should see it doesn't compile.

##### **Related issues**

Don't think so. Related to https://github.com/jhipster/jhipster-core/issues/459.

##### **Suggest a Fix**

#11588

##### **JHipster Version(s)**

master

##### **JHipster configuration**

```
application
  config {
    baseName testWithEnums
  }}

entity MyEntity {
  myField MyEnum
}

enum MyEnum {
  AAA(aaa),
  BBB(bbb)
}
```

##### **Entity configuration(s) `entityName.json` files generated in the `.jhipster` directory**

Just generate an app with the provided JDL, it should do the trick.

##### **Browsers and Operating System**

Irrelevant.

Pull request:
Fix enums
Fixes #11587

Also added tests and refactored the code

Patch:
diff --git a/.github/workflows/webflux.yml b/.github/workflows/webflux.yml
index f168b996dd..3e225c0202 100644
--- a/.github/workflows/webflux.yml
+++ b/.github/workflows/webflux.yml
@@ -51,8 +51,8 @@ jobs:
                     - webflux-gateway-jwt
                     - webflux-gateway-oauth2
                     - webflux-couchbase
-                    - webflux-couchbase-session
                     - webflux-couchbase-es-oauth2
+                    - webflux-psql
                 include:
                     - app-type: webflux-mongodb
                       entity: mongodb
@@ -84,12 +84,12 @@ jobs:
                       profile: prod
                       war: 0
                       protractor: 1
-                    - app-type: webflux-couchbase-session
+                    - app-type: webflux-couchbase-es-oauth2
                       entity: none
                       profile: prod
                       war: 0
                       protractor: 1
-                    - app-type: webflux-couchbase-es-oauth2
+                    - app-type: webflux-psql
                       entity: none
                       profile: prod
                       war: 0
diff --git a/cli/utils.js b/cli/utils.js
index f19b992c50..8ce4f7a772 100644
--- a/cli/utils.js
+++ b/cli/utils.js
@@ -220,7 +220,7 @@ const createYeomanEnv = packagePatterns => {
     const env = yeoman.createEnv();
     // Register jhipster generators.
     env.lookup({ packagePaths: [path.join(__dirname, '..')] });
-    if (packagePatterns) {
+    if (packagePatterns && packagePatterns.length > 0) {
         // Lookup for blueprints.
         env.lookup({ filterPaths: true, packagePatterns });
     }
diff --git a/generators/client/templates/angular/webpack/webpack.common.js.ejs b/generators/client/templates/angular/webpack/webpack.common.js.ejs
index 9f3a25e8f3..f259b350ef 100644
--- a/generators/client/templates/angular/webpack/webpack.common.js.ejs
+++ b/generators/client/templates/angular/webpack/webpack.common.js.ejs
@@ -34,7 +34,7 @@ module.exports = (options) => ({
     resolve: {
         extensions: ['.ts', '.js'],
         modules: ['node_modules'],
-        mainFields: [ 'es2015', 'browser', 'module', 'main'],
+        mainFields: ['browser', 'module', 'main'],
         alias: utils.mapTypescriptAliasToWebpackAlias()
     },
     stats: {
diff --git a/generators/entity-client/files.js b/generators/entity-client/files.js
index c6d9b57524..59ab759932 100644
--- a/generators/entity-client/files.js
+++ b/generators/entity-client/files.js
@@ -270,7 +270,11 @@ function addEnumerationFiles(generator, templateDir, clientFolder) {
     generator.fields.forEach(field => {
         if (field.fieldIsEnum === true) {
             const enumFileName = _.kebabCase(field.fieldType);
-            const enumInfo = utils.buildEnumInfo(field, generator.angularAppName, generator.packageName, generator.clientRootFolder);
+            const enumInfo = {
+                ...utils.getEnumInfo(field, generator.clientRootFolder),
+                angularAppName: generator.angularAppName,
+                packageName: generator.packageName
+            };
             if (!generator.skipClient) {
                 generator.template(
                     `${generator.fetchFromInstalledJHipster(
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-update.component.html.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-update.component.html.ejs
index 2197c7473c..d5ded6f3d3 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-update.component.html.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-update.component.html.ejs
@@ -55,10 +55,10 @@ _%>
     <%_ if (fields[idx].fieldIsEnum) { _%>
                     <select class="form-control" name="<%= fieldName %>" formControlName="<%= fieldName %>" id="field_<%= fieldName %>">
         <%_ const enumPrefix = angularAppName + '.'+ fieldType;
-            const values = fields[idx].fieldValues.replace(/\s/g, '').split(',');
+            const values = getEnumValuesWithCustomValues(fields[idx].fieldValues);
             for (key in values) {
-                const value = values[key]; _%>
-                        <option value="<%= value %>"><% if (enableTranslation) { %>{{ '<%= enumPrefix %>.<%= value %>' | translate }}<% } else { %><%= value %><% } %></option>
+                const enumValue = values[key]; _%>
+                        <option value="<%= enumValue.name %>"><% if (enableTranslation) { %>{{ '<%= enumPrefix %>.<%= enumValue.name %>' | translate }}<% } else { %><%= enumValue.value %><% } %></option>
         <%_ } _%>
                     </select>
     <%_ } else { _%>
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/enumerations/enum.model.ts.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/enumerations/enum.model.ts.ejs
index 4a76dabb5f..22d7f2068b 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/enumerations/enum.model.ts.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/enumerations/enum.model.ts.ejs
@@ -17,11 +17,7 @@
  limitations under the License.
 -%>
 export const enum <%= enumName %> {
-<% enumsWithCustomValue.forEach((enumWithCustomValue, index) => { %>
-  <% if (!enumWithCustomValue.value) { %>
-  <%= enumWithCustomValue.name %> = '<%= enumWithCustomValue.name %>'
-  <% } else { %>
-  <%= enumWithCustomValue.name %> = '<%= enumWithCustomValue.value %>'
-  <% } %><% if (index < enumsWithCustomValue.length - 1) { %>,<% } %>
+<% enumValues.forEach((enumValue, index) => { %>
+  <%= enumValue.name %> = '<%= enumValue.value %>'<% if (index < enumValues.length - 1) { %>,<% } %>
 <% }); %>
 }
diff --git a/generators/entity-client/templates/react/src/main/webapp/app/entities/entity-update.tsx.ejs b/generators/entity-client/templates/react/src/main/webapp/app/entities/entity-update.tsx.ejs
index b0f1e5d0c3..3d124dedff 100644
--- a/generators/entity-client/templates/react/src/main/webapp/app/entities/entity-update.tsx.ejs
+++ b/generators/entity-client/templates/react/src/main/webapp/app/entities/entity-update.tsx.ejs
@@ -278,7 +278,7 @@ export const <%= entityReactName %>Update = (props: I<%= entityReactName %>Updat
             />
           <%_
             } else if (fields[idx].fieldIsEnum) {
-              const values = fields[idx].fieldValues.replace(/\s/g, '').split(',');
+              const enumValues = getEnumValuesWithCustomValues(fields[idx].fieldValues);
           _%>
             <Label id="<%= fieldName %>Label" for="<%= entityFileName %>-<%= fieldName %>">
               <Translate contentKey="<%= i18nKeyPrefix %>.<%= fieldName %>">
@@ -290,21 +290,20 @@ export const <%= entityReactName %>Update = (props: I<%= entityReactName %>Updat
               type="select"
               className="form-control"
               name="<%= fieldName %>"
-              value={(!isNew && <%= entityInstance %>Entity.<%= fieldName %>) || '<%= values[0] %>'}
+              value={(!isNew && <%= entityInstance %>Entity.<%= fieldName %>) || '<%= enumValues[0].name %>'}
             >
             <%_
               const enumPrefix = angularAppName + '.'+ fieldType;
-              for (key in values) {
-                  const value = values[key];
+              enumValues.forEach(enumValue => {
             _%>
-              <option value="<%= value %>">
+              <option value="<%= enumValue.name %>">
               <%_ if (enableTranslation) { _%>
-                {translate("<%= enumPrefix %>.<%= value %>")}
+                {translate("<%= enumPrefix %>.<%= enumValue.name %>")}
               <%_ } else { _%>
-                <%= value %>
+                <%= enumValue.value %>
               <%_ } _%>
               </option>
-            <%_ } _%>
+            <%_ }); _%>
             </AvInput>
           <%_ } else if (['Integer', 'Long', 'Float', 'Double'].includes(fieldType)) { _%>
             <Label id="<%= fieldName %>Label" for="<%= entityFileName %>-<%= fieldName %>">
diff --git a/generators/entity-client/templates/react/src/main/webapp/app/entities/enumerations/enum.model.ts.ejs b/generators/entity-client/templates/react/src/main/webapp/app/entities/enumerations/enum.model.ts.ejs
index e57574c6e1..22d7f2068b 100644
--- a/generators/entity-client/templates/react/src/main/webapp/app/entities/enumerations/enum.model.ts.ejs
+++ b/generators/entity-client/templates/react/src/main/webapp/app/entities/enumerations/enum.model.ts.ejs
@@ -17,11 +17,7 @@
  limitations under the License.
 -%>
 export const enum <%= enumName %> {
-<% enumsWithCustomValue.forEach((enumWithCustomValue, index) => { %>
-<% if (!enumWithCustomValue.value) { %>
-  <%= enumWithCustomValue.name %> = '<%= enumWithCustomValue.name %>'
-<% } else { %>
-  <%= enumWithCustomValue.name %> = '<%= enumWithCustomValue.value %>'
-<% } %><% if (index < enumsWithCustomValue.length - 1) { %>,<% } %>
+<% enumValues.forEach((enumValue, index) => { %>
+  <%= enumValue.name %> = '<%= enumValue.value %>'<% if (index < enumValues.length - 1) { %>,<% } %>
 <% }); %>
 }
diff --git a/generators/entity-i18n/files.js b/generators/entity-i18n/files.js
index b1253b4279..16694a9aca 100644
--- a/generators/entity-i18n/files.js
+++ b/generators/entity-i18n/files.js
@@ -32,7 +32,11 @@ function writeFiles() {
         writeEnumFiles() {
             this.fields.forEach(field => {
                 if (field.fieldIsEnum === true) {
-                    const enumInfo = utils.buildEnumInfo(field, this.angularAppName, this.packageName, this.clientRootFolder);
+                    const enumInfo = {
+                        ...utils.getEnumInfo(field, this.clientRootFolder),
+                        angularAppName: this.angularAppName,
+                        packageName: this.packageName
+                    };
 
                     // Copy for each
                     if (!this.skipClient && this.enableTranslation) {
diff --git a/generators/entity-i18n/templates/i18n/enum.json.ejs b/generators/entity-i18n/templates/i18n/enum.json.ejs
index 616b166941..f3a78f0f7c 100644
--- a/generators/entity-i18n/templates/i18n/enum.json.ejs
+++ b/generators/entity-i18n/templates/i18n/enum.json.ejs
@@ -19,8 +19,8 @@
 {
     "<%= angularAppName %>": {
         "<%= enumName %>" : {
-            "null": ""<% for (enumId in enums) { %>,
-            "<%= enums[enumId] %>": "<%= enums[enumId] %>"<% } %>
+            "null": ""<% enumValues.forEach(enumValue => { %>,
+            "<%= enumValue.name %>": "<%= enumValue.value %>"<% }); %>
         }
     }
 }
diff --git a/generators/entity-server/files.js b/generators/entity-server/files.js
index 38dd45262d..0d7a36e81c 100644
--- a/generators/entity-server/files.js
+++ b/generators/entity-server/files.js
@@ -386,20 +386,27 @@ function writeFiles() {
 
         writeEnumFiles() {
             this.fields.forEach(field => {
-                if (field.fieldIsEnum === true) {
-                    const fieldType = field.fieldType;
-                    const enumInfo = utils.buildEnumInfo(field, this.angularAppName, this.packageName, this.clientRootFolder);
-                    if (!this.skipServer) {
-                        this.template(
-                            `${this.fetchFromInstalledJHipster(
-                                'entity-server/templates'
-                            )}/${SERVER_MAIN_SRC_DIR}package/domain/enumeration/Enum.java.ejs`,
-                            `${SERVER_MAIN_SRC_DIR}${this.packageFolder}/domain/enumeration/${fieldType}.java`,
-                            this,
-                            {},
-                            enumInfo
-                        );
-                    }
+                if (!field.fieldIsEnum) {
+                    return;
+                }
+                const fieldType = field.fieldType;
+                const enumInfo = {
+                    ...utils.getEnumInfo(field, this.clientRootFolder),
+                    angularAppName: this.angularAppName,
+                    packageName: this.packageName
+                };
+                // eslint-disable-next-line no-console
+                if (!this.skipServer) {
+                    const pathToTemplateFile = `${this.fetchFromInstalledJHipster(
+                        'entity-server/templates'
+                    )}/${SERVER_MAIN_SRC_DIR}package/domain/enumeration/Enum.java.ejs`;
+                    this.template(
+                        pathToTemplateFile,
+                        `${SERVER_MAIN_SRC_DIR}${this.packageFolder}/domain/enumeration/${fieldType}.java`,
+                        this,
+                        {},
+                        enumInfo
+                    );
                 }
             });
         }
diff --git a/generators/entity-server/templates/src/main/java/package/domain/enumeration/Enum.java.ejs b/generators/entity-server/templates/src/main/java/package/domain/enumeration/Enum.java.ejs
index 00a9f3d294..50ba9ba8e2 100644
--- a/generators/entity-server/templates/src/main/java/package/domain/enumeration/Enum.java.ejs
+++ b/generators/entity-server/templates/src/main/java/package/domain/enumeration/Enum.java.ejs
@@ -22,5 +22,29 @@ package <%= packageName %>.domain.enumeration;
  * The <%= enumName %> enumeration.
  */
 public enum <%= enumName %> {
-    <%= enumValues %>
+<%_ if (withoutCustomValues) { _%>
+    <%= enumValues.map(enumValue => enumValue.name).join(', ') %>
+<%_ } else {
+    enumValues.forEach((enumWithCustomValue, index) => {
+        if (enumWithCustomValue.name === enumWithCustomValue.value) { _%>
+    <%= enumWithCustomValue.name %><% if (index < enumValues.length - 1) { %>,<% } else { %>;<% } %>
+        <%_ } else { _%>
+    <%= enumWithCustomValue.name %>("<%= enumWithCustomValue.value %>")<% if (index < enumValues.length - 1) { %>,<% } else { %>;<% } %>
+        <%_ }
+    }); _%>
+
+    private<% if (withCustomValues) { %> final<% } %> String value;
+
+<%_ if (withSomeCustomValues) { _%>
+    <%= enumName %>() {}
+<%_ } _%>
+
+    <%= enumName %>(String value) {
+        this.value = value;
+    }
+
+    public String getValue() {
+        return value;
+    }
+<%_ } _%>
 }
diff --git a/generators/entity-server/templates/src/main/resources/config/liquibase/fake-data/table.csv.ejs b/generators/entity-server/templates/src/main/resources/config/liquibase/fake-data/table.csv.ejs
index 2738acc4e2..b8542479ee 100644
--- a/generators/entity-server/templates/src/main/resources/config/liquibase/fake-data/table.csv.ejs
+++ b/generators/entity-server/templates/src/main/resources/config/liquibase/fake-data/table.csv.ejs
@@ -138,8 +138,8 @@ for (lineNb = 1; lineNb <= numberOfRows; lineNb++) {
         }
         if (fields[idx].fieldIsEnum) {
             if (fields[idx].fieldValues.length !== 0) {
-                const enums = fields[idx].fieldValues.split(',');
-                data = enums[this.faker.random.number(enums.length-1)];
+                const enumValues = getEnumValuesWithCustomValues(fields[idx].fieldValues);
+                data = enumValues[this.faker.random.number(enumValues.length-1)].name;
             } else {
                 data = '';
             }
diff --git a/generators/generator-base.js b/generators/generator-base.js
index 6eee3cbef6..830f3cbcae 100644
--- a/generators/generator-base.js
+++ b/generators/generator-base.js
@@ -2177,4 +2177,26 @@ module.exports = class extends PrivateBase {
         }
         return this._needleApi;
     }
+
+    /**
+     * From an enum's values (with or without custom values), returns the enum's values without custom values.
+     * @param {String} enumValues - an enum's values.
+     * @return {Array<String>} the formatted enum's values.
+     */
+    getEnumValuesWithCustomValues(enumValues) {
+        if (!enumValues || enumValues === '') {
+            throw new Error('Enumeration values must be passed to get the formatted values.');
+        }
+        return enumValues.split(',').map(enumValue => {
+            if (!enumValue.includes('(')) {
+                return { name: enumValue.trim(), value: enumValue.trim() };
+            }
+            // eslint-disable-next-line no-unused-vars
+            const matched = /\s*(.+?)\s*\((.+?)\)/.exec(enumValue);
+            return {
+                name: matched[1],
+                value: matched[2]
+            };
+        });
+    }
 };
diff --git a/generators/generator-constants.js b/generators/generator-constants.js
index 623ce3545c..bd80f720e3 100644
--- a/generators/generator-constants.js
+++ b/generators/generator-constants.js
@@ -66,7 +66,7 @@ const DOCKER_JHIPSTER_IMPORT_DASHBOARDS = 'jhipster/jhipster-import-dashboards:v
 const DOCKER_JHIPSTER_ZIPKIN = 'jhipster/jhipster-zipkin:v4.1.0';
 const DOCKER_TRAEFIK = 'traefik:1.7.24'; // waiting for https://github.com/jhipster/generator-jhipster/issues/11198
 const DOCKER_CONSUL = 'consul:1.7.2';
-const DOCKER_CONSUL_CONFIG_LOADER = 'jhipster/consul-config-loader:v0.3.0';
+const DOCKER_CONSUL_CONFIG_LOADER = 'jhipster/consul-config-loader:v0.3.1';
 const DOCKER_PROMETHEUS = 'prom/prometheus:v2.17.1';
 const DOCKER_PROMETHEUS_ALERTMANAGER = 'prom/alertmanager:v0.20.0';
 const DOCKER_GRAFANA = 'grafana/grafana:6.7.2';
diff --git a/generators/server/files.js b/generators/server/files.js
index edc796bb7e..d39df0cce5 100644
--- a/generators/server/files.js
+++ b/generators/server/files.js
@@ -1659,7 +1659,7 @@ const serverFiles = {
         },
         {
             condition: generator =>
-                generator.authenticationType === 'oauth2' && ['sql', 'mongodb', 'couchbase'].includes(generator.databaseType),
+                generator.authenticationType === 'oauth2' && ['sql', 'mongodb', 'couchbase', 'neo4j'].includes(generator.databaseType),
             path: SERVER_MAIN_SRC_DIR,
             templates: [
                 {
@@ -1855,7 +1855,8 @@ const serverFiles = {
         },
         {
             // TODO : add tests for reactive
-            condition: generator => !generator.skipUserManagement && ['sql', 'mongodb', 'couchbase'].includes(generator.databaseType),
+            condition: generator =>
+                !generator.skipUserManagement && ['sql', 'mongodb', 'couchbase', 'neo4j'].includes(generator.databaseType),
             path: SERVER_TEST_SRC_DIR,
             templates: [
                 {
diff --git a/generators/server/templates/src/main/java/package/domain/PersistentAuditEvent.java.ejs b/generators/server/templates/src/main/java/package/domain/PersistentAuditEvent.java.ejs
index e8e598f4a3..675deebf78 100644
--- a/generators/server/templates/src/main/java/package/domain/PersistentAuditEvent.java.ejs
+++ b/generators/server/templates/src/main/java/package/domain/PersistentAuditEvent.java.ejs
@@ -29,6 +29,7 @@ import org.neo4j.springframework.data.core.schema.Node;
 import org.neo4j.springframework.data.core.schema.Property;
 import org.neo4j.springframework.data.core.schema.Relationship;
 import org.neo4j.springframework.data.core.support.UUIDStringGenerator;
+import org.springframework.data.annotation.Transient;
 <%_ } else if (databaseType === 'couchbase') { _%>
 import org.springframework.data.annotation.Id;
 import com.couchbase.client.java.repository.annotation.Field;
@@ -122,6 +123,8 @@ public class PersistentAuditEvent implements Serializable {
     <%_ } _%>
     <%_ if (databaseType === 'mongodb' || databaseType === 'couchbase') { _%>
     @Field("event_date")
+    <%_ } else if (databaseType === 'neo4j') { _%>
+    @Property("event_date")
     <%_ } _%>
     private Instant auditEventDate;
 
@@ -130,6 +133,8 @@ public class PersistentAuditEvent implements Serializable {
     <%_ } _%>
     <%_ if (databaseType === 'mongodb' || databaseType === 'couchbase') { _%>
     @Field("event_type")
+    <%_ } else if (databaseType === 'neo4j') { _%>
+    @Property("event_type")
     <%_ } _%>
     private String auditEventType;
 
@@ -143,6 +148,9 @@ public class PersistentAuditEvent implements Serializable {
     @Transient
         <%_ } _%>
     <%_ } _%>
+    <%_ if (databaseType === 'neo4j') { _%>
+    @Transient
+    <%_ } _%>
     private Map<String, String> data = new HashMap<>();
 
     <%_ if (databaseType === 'sql') { _%>
diff --git a/generators/server/templates/src/main/java/package/web/rest/errors/ExceptionTranslator.java.ejs b/generators/server/templates/src/main/java/package/web/rest/errors/ExceptionTranslator.java.ejs
index 8822ce4f99..485a7332a0 100644
--- a/generators/server/templates/src/main/java/package/web/rest/errors/ExceptionTranslator.java.ejs
+++ b/generators/server/templates/src/main/java/package/web/rest/errors/ExceptionTranslator.java.ejs
@@ -25,6 +25,9 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.dao.ConcurrencyFailureException;
 <%_ } _%>
 import org.springframework.http.ResponseEntity;
+<%_ if (reactive && databaseType === 'sql') { _%>
+import org.springframework.stereotype.Component;
+<%_ } _%>
 import org.springframework.validation.BindingResult;
 <%_ if (!reactive) { _%>
 import org.springframework.web.bind.MethodArgumentNotValidException;
diff --git a/generators/utils.js b/generators/utils.js
index 81c1ae0000..69e549e18f 100644
--- a/generators/utils.js
+++ b/generators/utils.js
@@ -56,6 +56,7 @@ module.exports = {
     deepFind,
     getJavadoc,
     buildEnumInfo,
+    getEnumInfo,
     copyObjectProps,
     decodeBase64,
     getAllJhipsterConfig,
@@ -453,6 +454,29 @@ function getJavadoc(text, indentSize) {
 
 /**
  * Build an enum object
+ * @param {Object} field - entity field
+ * @param {String} clientRootFolder - the client's root folder
+ * @return {Object} the enum info.
+ */
+function getEnumInfo(field, clientRootFolder) {
+    const fieldType = field.fieldType;
+    // Todo: check if the next line does a side-effect and refactor it.
+    field.enumInstance = _.lowerFirst(fieldType);
+    const enums = field.fieldValues.split(',').map(fieldValue => fieldValue.trim());
+    const customValuesState = getCustomValuesState(enums);
+    return {
+        enumName: fieldType,
+        enumInstance: field.enumInstance,
+        enums,
+        ...customValuesState,
+        enumValues: getEnums(enums, customValuesState),
+        clientRootFolder: clientRootFolder ? `${clientRootFolder}-` : ''
+    };
+}
+
+/**
+ * @Deprecated
+ * Build an enum object, deprecated use getEnumInfoInstead
  * @param {any} field : entity field
  * @param {string} angularAppName
  * @param {string} packageName
@@ -475,6 +499,12 @@ function buildEnumInfo(field, angularAppName, packageName, clientRootFolder) {
     };
 }
 
+/**
+ * @deprecated
+ * private function to remove for jhipster v7
+ * @param enums
+ * @return {*}
+ */
 function getEnumsWithCustomValue(enums) {
     return enums.reduce((enumsWithCustomValueArray, currentEnumValue) => {
         if (doesTheEnumValueHaveACustomValue(currentEnumValue)) {
@@ -489,6 +519,42 @@ function getEnumsWithCustomValue(enums) {
     }, []);
 }
 
+function getCustomValuesState(enumValues) {
+    const state = {
+        withoutCustomValue: 0,
+        withCustomValue: 0
+    };
+    enumValues.forEach(enumValue => {
+        if (doesTheEnumValueHaveACustomValue(enumValue)) {
+            state.withCustomValue++;
+        } else {
+            state.withoutCustomValue++;
+        }
+    });
+    return {
+        withoutCustomValues: state.withCustomValue === 0,
+        withSomeCustomValues: state.withCustomValue !== 0 && state.withoutCustomValue !== 0,
+        withCustomValues: state.withoutCustomValue === 0
+    };
+}
+
+function getEnums(enums, customValuesState) {
+    if (customValuesState.withoutCustomValues) {
+        return enums.map(enumValue => ({ name: enumValue, value: enumValue }));
+    }
+    return enums.map(enumValue => {
+        if (!doesTheEnumValueHaveACustomValue(enumValue)) {
+            return { name: enumValue.trim(), value: enumValue.trim() };
+        }
+        // eslint-disable-next-line no-unused-vars
+        const matched = /\s*(.+?)\s*\((.+?)\)/.exec(enumValue);
+        return {
+            name: matched[1],
+            value: matched[2]
+        };
+    });
+}
+
 function doesTheEnumValueHaveACustomValue(enumValue) {
     return enumValue.includes('(');
 }
diff --git a/package-lock.json b/package-lock.json
index 466d35ea65..9afe3706d3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6326,9 +6326,9 @@
             "dev": true
         },
         "yeoman-environment": {
-            "version": "2.9.3",
-            "resolved": "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-2.9.3.tgz",
-            "integrity": "sha512-W683tcesXmVXslYRbhnG9urYOJvRbsByH/ffhzp+G3tsXBsQUjRb5DMuhE3Nb932/cWmLl7jA/sONxEmlfTAcg==",
+            "version": "2.9.5",
+            "resolved": "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-2.9.5.tgz",
+            "integrity": "sha512-ntxV8VTZbP8QFuJZGT7vG8AsKeyGz8lXlfq2V2T5sl6SrU6UAEVgRreEGz9t+JbFGx1CSM/Ly2atG/avGuheyQ==",
             "requires": {
                 "chalk": "^2.4.1",
                 "debug": "^3.1.0",
@@ -6642,9 +6642,9 @@
             }
         },
         "yeoman-generator": {
-            "version": "4.8.2",
-            "resolved": "https://registry.npmjs.org/yeoman-generator/-/yeoman-generator-4.8.2.tgz",
-            "integrity": "sha512-4kJAf2u5mee8yO7Ph6e64KLHeC7sCSYPCP7YcCUjussBFzoMEqJ2+Dn2Yj41rBLArSBBmZOQ/e2bMYlh6qQ9ag==",
+            "version": "4.8.3",
+            "resolved": "https://registry.npmjs.org/yeoman-generator/-/yeoman-generator-4.8.3.tgz",
+            "integrity": "sha512-yDPHBhfglqiyYlqBnaAmcE/wPznwSx11HCGVCpnnsqpnp45HmdsuBtiFSNDcygiFmz1HmkFWRLWHTai/b+9eiQ==",
             "requires": {
                 "async": "^2.6.2",
                 "chalk": "^2.4.2",
@@ -6657,6 +6657,7 @@
                 "error": "^7.0.2",
                 "find-up": "^3.0.0",
                 "github-username": "^3.0.0",
+                "grouped-queue": "^1.1.0",
                 "istextorbinary": "^2.5.1",
                 "lodash": "^4.17.11",
                 "make-dir": "^3.0.0",
@@ -6695,6 +6696,23 @@
                         "locate-path": "^3.0.0"
                     }
                 },
+                "grouped-queue": {
+                    "version": "1.1.0",
+                    "resolved": "https://registry.npmjs.org/grouped-queue/-/grouped-queue-1.1.0.tgz",
+                    "integrity": "sha512-rZOFKfCqLhsu5VqjBjEWiwrYqJR07KxIkH4mLZlNlGDfntbb4FbMyGFP14TlvRPrU9S3Hnn/sgxbC5ZeN0no3Q==",
+                    "optional": true,
+                    "requires": {
+                        "lodash": "^4.17.15"
+                    },
+                    "dependencies": {
+                        "lodash": {
+                            "version": "4.17.15",
+                            "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+                            "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+                            "optional": true
+                        }
+                    }
+                },
                 "locate-path": {
                     "version": "3.0.0",
                     "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
diff --git a/package.json b/package.json
index 790df7cdb5..b1caf8d1ee 100644
--- a/package.json
+++ b/package.json
@@ -81,8 +81,8 @@
         "tabtab": "2.2.2",
         "through2": "3.0.1",
         "uuid": "3.3.3",
-        "yeoman-environment": "2.9.3",
-        "yeoman-generator": "4.8.2"
+        "yeoman-environment": "2.9.5",
+        "yeoman-generator": "4.8.3"
     },
     "devDependencies": {
         "@openapitools/openapi-generator-cli": "1.0.12-4.3.0",


Test patch:
diff --git a/generators/entity-client/templates/angular/src/test/javascript/spec/app/entities/entity-management.service.spec.ts.ejs b/generators/entity-client/templates/angular/src/test/javascript/spec/app/entities/entity-management.service.spec.ts.ejs
index 4a147cb8bb..7f3134c2e6 100644
--- a/generators/entity-client/templates/angular/src/test/javascript/spec/app/entities/entity-management.service.spec.ts.ejs
+++ b/generators/entity-client/templates/angular/src/test/javascript/spec/app/entities/entity-management.service.spec.ts.ejs
@@ -68,7 +68,7 @@ describe('Service Tests', () => {
                 const fieldType = field.fieldType;
             _%>
                 <%_ if (field.fieldIsEnum) { _%>
-                <%= fieldType + '.' + field.fieldValues.split(',')[0].replace(/(.+?)\(.*/, (match, firstGroup) => firstGroup) %>,
+                <%= fieldType + '.' + getEnumValuesWithCustomValues(field.fieldValues)[0].name %>,
                 <%_ } else if (fieldType === 'Boolean') { _%>
                 false,
                 <%_ } else if (['Integer', 'Long', 'Float', 'Double', 'BigDecimal', 'Duration'].includes(fieldType)) { _%>
diff --git a/generators/entity-server/templates/src/test/gatling/user-files/simulations/EntityGatlingTest.scala.ejs b/generators/entity-server/templates/src/test/gatling/user-files/simulations/EntityGatlingTest.scala.ejs
index 8c17ae2073..ee4b392fe2 100644
--- a/generators/entity-server/templates/src/test/gatling/user-files/simulations/EntityGatlingTest.scala.ejs
+++ b/generators/entity-server/templates/src/test/gatling/user-files/simulations/EntityGatlingTest.scala.ejs
@@ -188,7 +188,7 @@ class <%= entityClass %>GatlingTest extends Simulation {
             .body(StringBody("""{
                 "id":null
                 <%_ for (idx in fields) { _%>
-                , "<%= fields[idx].fieldName %>":<% if (fields[idx].fieldType === 'String') { %>"SAMPLE_TEXT"<% } else if (['Integer', 'BigDecimal'].includes(fields[idx].fieldType)) { %>"0"<% } else if (['Instant', 'ZonedDateTime', 'LocalDate'].includes(fields[idx].fieldType)) { %>"2020-01-01T00:00:00.000Z"<% } else if (fields[idx].fieldIsEnum) { %>"<%= fields[idx].fieldValues.split(',')[0] %>"<% } else { %>null<% } %>
+                , "<%= fields[idx].fieldName %>":<% if (fields[idx].fieldType === 'String') { %>"SAMPLE_TEXT"<% } else if (['Integer', 'BigDecimal'].includes(fields[idx].fieldType)) { %>"0"<% } else if (['Instant', 'ZonedDateTime', 'LocalDate'].includes(fields[idx].fieldType)) { %>"2020-01-01T00:00:00.000Z"<% } else if (fields[idx].fieldIsEnum) { %>"<%= getEnumValuesWithCustomValues(fields[idx].fieldValues)[0].name %>"<% } else { %>null<% } %>
                 <%_ } _%>
                 }""")).asJson
             .check(status.is(201))
diff --git a/generators/entity-server/templates/src/test/java/package/web/rest/EntityResourceIT.java.ejs b/generators/entity-server/templates/src/test/java/package/web/rest/EntityResourceIT.java.ejs
index ddb1efa7b6..55e657f55b 100644
--- a/generators/entity-server/templates/src/test/java/package/web/rest/EntityResourceIT.java.ejs
+++ b/generators/entity-server/templates/src/test/java/package/web/rest/EntityResourceIT.java.ejs
@@ -239,10 +239,10 @@ public class <%= entityClass %>ResourceIT <% if (databaseType === 'cassandra') {
     let enumValue1;
     let enumValue2;
     if (isEnum) {
-        const values = fields[idx].fieldValues.replace(/\s/g, '').split(',');
-        enumValue1 = values[0];
-        if (values.length > 1) {
-            enumValue2 = values[1];
+        const enumValues = getEnumValuesWithCustomValues(fields[idx].fieldValues);
+        enumValue1 = enumValues[0];
+        if (enumValues.length > 1) {
+            enumValue2 = enumValues[1];
         } else {
             enumValue2 = enumValue1;
         }
@@ -374,8 +374,8 @@ public class <%= entityClass %>ResourceIT <% if (databaseType === 'cassandra') {
     private static final String <%= updatedValueName %>_CONTENT_TYPE = "image/png";
     <%_ } else if (isEnum) { _%>
 
-    private static final <%= fieldType %> <%= defaultValueName %> = <%= fieldType %>.<%= enumValue1 %>;
-    private static final <%= fieldType %> <%= updatedValueName %> = <%= fieldType %>.<%= enumValue2 %>;
+    private static final <%= fieldType %> <%= defaultValueName %> = <%= fieldType %>.<%= enumValue1.name %>;
+    private static final <%= fieldType %> <%= updatedValueName %> = <%= fieldType %>.<%= enumValue2.name %>;
     <%_ } } _%>
 
     @Autowired
diff --git a/test-integration/samples/.jhipster/FieldTestEnumWithValue.json b/test-integration/samples/.jhipster/FieldTestEnumWithValue.json
new file mode 100644
index 0000000000..0a1ebfb5c7
--- /dev/null
+++ b/test-integration/samples/.jhipster/FieldTestEnumWithValue.json
@@ -0,0 +1,32 @@
+{
+    "name": "FieldTestEnumWithValue",
+    "fields": [
+        {
+            "fieldName": "myFieldA",
+            "fieldType": "MyEnumA",
+            "fieldValues": "AAA,BBB"
+        },
+        {
+            "fieldName": "myFieldB",
+            "fieldType": "MyEnumB",
+            "fieldValues": "AAA (aaa_aaa),BBB"
+        },
+        {
+            "fieldName": "myFieldC",
+            "fieldType": "MyEnumC",
+            "fieldValues": "AAA (aaa_aaa),BBB (b and b)"
+        }
+    ],
+    "relationships": [],
+    "changelogDate": "20200415193919",
+    "entityTableName": "entity_with_enums",
+    "dto": "no",
+    "pagination": "no",
+    "service": "no",
+    "jpaMetamodelFiltering": false,
+    "fluentMethods": true,
+    "readOnly": false,
+    "embedded": false,
+    "clientRootFolder": "",
+    "applications": "*"
+}
diff --git a/test-integration/samples/jdl-default/app.jdl b/test-integration/samples/jdl-default/app.jdl
index 6b8fc66f8e..c5e73547db 100644
--- a/test-integration/samples/jdl-default/app.jdl
+++ b/test-integration/samples/jdl-default/app.jdl
@@ -40,9 +40,9 @@ entity Operation {
 }
 
 enum BankAccountType {
-  CHECKING,
-  SAVINGS,
-  LOAN
+  CHECKING (checking_account),
+  SAVINGS (savings_account),
+  LOAN (loan_account)
 }
 
 entity Department {
diff --git a/test-integration/samples/webflux-psql/.yo-rc.json b/test-integration/samples/webflux-psql/.yo-rc.json
new file mode 100644
index 0000000000..9d7be28144
--- /dev/null
+++ b/test-integration/samples/webflux-psql/.yo-rc.json
@@ -0,0 +1,26 @@
+{
+    "generator-jhipster": {
+        "applicationType": "monolith",
+        "reactive": true,
+        "baseName": "sampleWebfluxPsql",
+        "packageName": "io.github.jhipster.sample",
+        "packageFolder": "io/github/jhipster/sample",
+        "authenticationType": "jwt",
+        "cacheProvider": "no",
+        "enableHibernateCache": false,
+        "websocket": false,
+        "databaseType": "sql",
+        "devDatabaseType": "h2Disk",
+        "prodDatabaseType": "postgresql",
+        "searchEngine": false,
+        "buildTool": "maven",
+        "enableTranslation": true,
+        "nativeLanguage": "en",
+        "languages": ["en", "fr"],
+        "testFrameworks": ["gatling", "protractor"],
+        "serverPort": "8080",
+        "jhiPrefix": "jhi",
+        "clientPackageManager": "npm",
+        "clientFramework": "angularX"
+    }
+}
diff --git a/test-integration/scripts/11-generate-entities.sh b/test-integration/scripts/11-generate-entities.sh
index 68e8dc75c9..b227733348 100755
--- a/test-integration/scripts/11-generate-entities.sh
+++ b/test-integration/scripts/11-generate-entities.sh
@@ -100,6 +100,7 @@ elif [[ "$JHI_ENTITY" == "sqlfull" ]]; then
     moveEntity FieldTestServiceImplEntity
     moveEntity FieldTestInfiniteScrollEntity
     moveEntity FieldTestPaginationEntity
+    moveEntity FieldTestEnumWithValue
 
     moveEntity TestEntity
     moveEntity TestMapstruct
@@ -140,6 +141,7 @@ elif [[ "$JHI_ENTITY" == "sql" ]]; then
     moveEntity FieldTestServiceImplEntity
     moveEntity FieldTestInfiniteScrollEntity
     moveEntity FieldTestPaginationEntity
+    moveEntity FieldTestEnumWithValue
 
     moveEntity EntityWithDTO
     moveEntity EntityWithPaginationAndDTO
diff --git a/test/entity.spec.js b/test/entity.spec.js
index 24c14e71dd..79eff3506a 100644
--- a/test/entity.spec.js
+++ b/test/entity.spec.js
@@ -850,5 +850,76 @@ describe('JHipster generator for entity', () => {
                 });
             });
         });
+
+        context('when generating enums', () => {
+            let enumWithoutCustomValuesPath;
+            let enumWithSomeCustomValuesPath;
+            let enumWithOnlyCustomValuesPath;
+
+            before(done => {
+                enumWithoutCustomValuesPath = `${SERVER_MAIN_SRC_DIR}com/mycompany/myapp/domain/enumeration/MyEnumA.java`;
+                enumWithSomeCustomValuesPath = `${SERVER_MAIN_SRC_DIR}com/mycompany/myapp/domain/enumeration/MyEnumB.java`;
+                enumWithOnlyCustomValuesPath = `${SERVER_MAIN_SRC_DIR}com/mycompany/myapp/domain/enumeration/MyEnumC.java`;
+                helpers
+                    .run(require.resolve('../generators/entity'))
+                    .inTmpDir(dir => {
+                        fse.copySync(path.join(__dirname, '../test/templates/enums'), dir);
+                    })
+                    .withArguments(['A'])
+                    .on('end', done);
+            });
+
+            context('for enum content without custom values', () => {
+                it('generates the java enum content', () => {
+                    assert.fileContent(enumWithoutCustomValuesPath, /AAA,\s+BBB/);
+                });
+                it('does not generate a private field', () => {
+                    assert.noFileContent(enumWithoutCustomValuesPath, /private final String value;/);
+                });
+                it('does not generate an empty constructor', () => {
+                    assert.noFileContent(enumWithoutCustomValuesPath, /MyEnumA\(\)/);
+                });
+                it('does not generate a non-empty constructor', () => {
+                    assert.noFileContent(enumWithoutCustomValuesPath, /MyEnumA\(String value\)/);
+                });
+                it('does not generate a getter for the value', () => {
+                    assert.noFileContent(enumWithoutCustomValuesPath, /public String getValue\(\)/);
+                });
+            });
+            context('for enum content with some custom values', () => {
+                it('generates the java enum content', () => {
+                    assert.fileContent(enumWithSomeCustomValuesPath, /AAA\("aaa_aaa"\),\s+BBB;/);
+                });
+                it('generates a non-final private field', () => {
+                    assert.fileContent(enumWithSomeCustomValuesPath, /private String value;/);
+                });
+                it('generates an empty constructor', () => {
+                    assert.fileContent(enumWithSomeCustomValuesPath, /MyEnumB\(\)/);
+                });
+                it('generates a non-empty constructor', () => {
+                    assert.fileContent(enumWithSomeCustomValuesPath, /MyEnumB\(String value\)/);
+                });
+                it('generates a getter for the value', () => {
+                    assert.fileContent(enumWithSomeCustomValuesPath, /public String getValue\(\)/);
+                });
+            });
+            context('for enum content with only custom values', () => {
+                it('generates the java enum content', () => {
+                    assert.fileContent(enumWithOnlyCustomValuesPath, /AAA\("aaa_aaa"\),\s+BBB\("bbb"\);/);
+                });
+                it('generates a final private field', () => {
+                    assert.fileContent(enumWithOnlyCustomValuesPath, /private final String value;/);
+                });
+                it('does not generate an empty constructor', () => {
+                    assert.noFileContent(enumWithOnlyCustomValuesPath, /MyEnumC\(\)/);
+                });
+                it('generates a non-empty constructor', () => {
+                    assert.fileContent(enumWithOnlyCustomValuesPath, /MyEnumC\(String value\)/);
+                });
+                it('generates a getter for the value', () => {
+                    assert.fileContent(enumWithOnlyCustomValuesPath, /public String getValue\(\)/);
+                });
+            });
+        });
     });
 });
diff --git a/test/generator-base.spec.js b/test/generator-base.spec.js
index d56c744fba..e530ddf2a9 100644
--- a/test/generator-base.spec.js
+++ b/test/generator-base.spec.js
@@ -268,7 +268,6 @@ describe('Generator Base', () => {
             });
         });
     });
-
     describe('writeFilesToDisk', () => {
         describe('when called with default angular client options', () => {
             it('should produce correct files', () => {
@@ -304,4 +303,47 @@ describe('Generator Base', () => {
             });
         });
     });
+    describe('getEnumValuesWithCustomValues', () => {
+        describe('when not passing anything', () => {
+            it('should fail', () => {
+                expect(() => BaseGenerator.getEnumValuesWithCustomValues()).to.throw(
+                    /^Enumeration values must be passed to get the formatted values\.$/
+                );
+            });
+        });
+        describe('when passing an empty string', () => {
+            it('should fail', () => {
+                expect(() => BaseGenerator.getEnumValuesWithCustomValues('')).to.throw(
+                    /^Enumeration values must be passed to get the formatted values\.$/
+                );
+            });
+        });
+        describe('when passing a string without custom enum values', () => {
+            it('should return a formatted list', () => {
+                expect(BaseGenerator.getEnumValuesWithCustomValues('FRANCE, ENGLAND, ICELAND')).to.deep.equal([
+                    { name: 'FRANCE', value: 'FRANCE' },
+                    { name: 'ENGLAND', value: 'ENGLAND' },
+                    { name: 'ICELAND', value: 'ICELAND' }
+                ]);
+            });
+        });
+        describe('when passing a string with some custom enum values', () => {
+            it('should return a formatted list', () => {
+                expect(BaseGenerator.getEnumValuesWithCustomValues('FRANCE(france), ENGLAND, ICELAND (viking_country)')).to.deep.equal([
+                    { name: 'FRANCE', value: 'france' },
+                    { name: 'ENGLAND', value: 'ENGLAND' },
+                    { name: 'ICELAND', value: 'viking_country' }
+                ]);
+            });
+        });
+        describe('when passing a string custom enum values for each value', () => {
+            it('should return a formatted list', () => {
+                expect(BaseGenerator.getEnumValuesWithCustomValues('FRANCE(france), ENGLAND(england), ICELAND (iceland)')).to.deep.equal([
+                    { name: 'FRANCE', value: 'france' },
+                    { name: 'ENGLAND', value: 'england' },
+                    { name: 'ICELAND', value: 'iceland' }
+                ]);
+            });
+        });
+    });
 });
diff --git a/test/templates/enums/.jhipster/A.json b/test/templates/enums/.jhipster/A.json
new file mode 100644
index 0000000000..ba5c0e8a8d
--- /dev/null
+++ b/test/templates/enums/.jhipster/A.json
@@ -0,0 +1,32 @@
+{
+    "name": "A",
+    "fields": [
+        {
+            "fieldName": "myFieldA",
+            "fieldType": "MyEnumA",
+            "fieldValues": "AAA,BBB"
+        },
+        {
+            "fieldName": "myFieldB",
+            "fieldType": "MyEnumB",
+            "fieldValues": "AAA (aaa_aaa),BBB"
+        },
+        {
+            "fieldName": "myFieldC",
+            "fieldType": "MyEnumC",
+            "fieldValues": "AAA (aaa_aaa),BBB (bbb)"
+        }
+    ],
+    "relationships": [],
+    "changelogDate": "20200415193919",
+    "entityTableName": "a",
+    "dto": "no",
+    "pagination": "no",
+    "service": "no",
+    "jpaMetamodelFiltering": false,
+    "fluentMethods": true,
+    "readOnly": false,
+    "embedded": false,
+    "clientRootFolder": "",
+    "applications": "*"
+}
diff --git a/test/templates/enums/.yo-rc.json b/test/templates/enums/.yo-rc.json
new file mode 100644
index 0000000000..cc69990c3f
--- /dev/null
+++ b/test/templates/enums/.yo-rc.json
@@ -0,0 +1,28 @@
+{
+  "generator-jhipster": {
+    "applicationType": "monolith",
+    "baseName": "sampleMysql",
+    "packageName": "com.mycompany.myapp",
+    "packageFolder": "com/mycompany/myapp",
+    "authenticationType": "session",
+    "cacheProvider": "ehcache",
+    "enableHibernateCache": true,
+    "websocket": "no",
+    "databaseType": "sql",
+    "devDatabaseType": "h2Disk",
+    "prodDatabaseType": "mysql",
+    "searchEngine": "no",
+      "buildTool": "maven",
+    "enableTranslation": true,
+    "nativeLanguage": "en",
+    "languages": [
+      "en",
+      "fr"
+    ],
+    "rememberMeKey": "2bb60a80889aa6e6767e9ccd8714982681152aa5",
+    "clientFramework": "angularX",
+    "testFrameworks": [
+      "gatling"
+    ]
+  }
+}
diff --git a/test/utils.spec.js b/test/utils.spec.js
index cf555fa51b..69608cf223 100644
--- a/test/utils.spec.js
+++ b/test/utils.spec.js
@@ -47,14 +47,145 @@ describe('JHipster Utils', () => {
             assert.objectContent(dst, src);
         });
     });
-    describe('::buildEnumFunction', () => {
-        it('describes all the properties of the entity', () => {
-            const packageName = 'com.package';
-            const angularAppName = 'myApp';
-            const clientRootFolder = 'root';
-            const entity = { enumName: 'entityName', fieldValues: 'field1, field2' };
-            const infos = utils.buildEnumInfo(entity, angularAppName, packageName, clientRootFolder);
-            assert.objectContent(infos, { packageName, angularAppName, clientRootFolder: `${clientRootFolder}-` });
+    describe('::getEnumInfo', () => {
+        describe('when passing field data', () => {
+            let enumInfo;
+
+            before(() => {
+                const clientRootFolder = 'root';
+                const field = { enumName: 'fieldName', fieldType: 'BigLetters', fieldValues: 'AAA, BBB' };
+                enumInfo = utils.getEnumInfo(field, clientRootFolder);
+            });
+
+            it("returns the enum's name", () => {
+                assert.strictEqual(enumInfo.enumName, 'BigLetters');
+            });
+            it("returns the enum's instance", () => {
+                assert.strictEqual(enumInfo.enumInstance, 'bigLetters');
+            });
+            it('returns the enums values', () => {
+                assert.deepStrictEqual(enumInfo.enums, ['AAA', 'BBB']);
+            });
+        });
+        describe("when the enums don't have custom values", () => {
+            let enumInfo;
+
+            before(() => {
+                const clientRootFolder = 'root';
+                const field = { enumName: 'fieldName', fieldValues: 'AAA, BBB' };
+                enumInfo = utils.getEnumInfo(field, clientRootFolder);
+            });
+
+            it('returns whether there are custom enums', () => {
+                assert.strictEqual(enumInfo.withoutCustomValues, true);
+                assert.strictEqual(enumInfo.withSomeCustomValues, false);
+                assert.strictEqual(enumInfo.withCustomValues, false);
+            });
+            it('returns the enums values', () => {
+                assert.deepStrictEqual(enumInfo.enumValues, [
+                    { name: 'AAA', value: 'AAA' },
+                    { name: 'BBB', value: 'BBB' }
+                ]);
+            });
+        });
+        describe('when some enums have custom values', () => {
+            let enumInfo;
+
+            before(() => {
+                const clientRootFolder = 'root';
+                const field = { enumName: 'fieldName', fieldValues: 'AAA(aaa), BBB' };
+                enumInfo = utils.getEnumInfo(field, clientRootFolder);
+            });
+
+            it('returns whether there are custom enums', () => {
+                assert.strictEqual(enumInfo.withoutCustomValues, false);
+                assert.strictEqual(enumInfo.withSomeCustomValues, true);
+                assert.strictEqual(enumInfo.withCustomValues, false);
+            });
+            it('returns the enums values', () => {
+                assert.deepStrictEqual(enumInfo.enumValues, [
+                    {
+                        name: 'AAA',
+                        value: 'aaa'
+                    },
+                    { name: 'BBB', value: 'BBB' }
+                ]);
+            });
+        });
+        describe('when all the enums have custom values', () => {
+            describe('without spaces inside them', () => {
+                let enumInfo;
+
+                before(() => {
+                    const clientRootFolder = 'root';
+                    const field = { enumName: 'fieldName', fieldValues: 'AAA(aaa), BBB(bbb)' };
+                    enumInfo = utils.getEnumInfo(field, clientRootFolder);
+                });
+
+                it('returns whether there are custom enums', () => {
+                    assert.strictEqual(enumInfo.withoutCustomValues, false);
+                    assert.strictEqual(enumInfo.withSomeCustomValues, false);
+                    assert.strictEqual(enumInfo.withCustomValues, true);
+                });
+                it('returns the enums values', () => {
+                    assert.deepStrictEqual(enumInfo.enumValues, [
+                        {
+                            name: 'AAA',
+                            value: 'aaa'
+                        },
+                        { name: 'BBB', value: 'bbb' }
+                    ]);
+                });
+            });
+            describe('with spaces inside them', () => {
+                let enumInfo;
+
+                before(() => {
+                    const clientRootFolder = 'root';
+                    const field = { enumName: 'fieldName', fieldValues: 'AAA(aaa), BBB(bbb and b)' };
+                    enumInfo = utils.getEnumInfo(field, clientRootFolder);
+                });
+
+                it('returns whether there are custom enums', () => {
+                    assert.strictEqual(enumInfo.withoutCustomValues, false);
+                    assert.strictEqual(enumInfo.withSomeCustomValues, false);
+                    assert.strictEqual(enumInfo.withCustomValues, true);
+                });
+                it('returns the enums values', () => {
+                    assert.deepStrictEqual(enumInfo.enumValues, [
+                        {
+                            name: 'AAA',
+                            value: 'aaa'
+                        },
+                        { name: 'BBB', value: 'bbb and b' }
+                    ]);
+                });
+            });
+        });
+        describe('when not passing a client root folder', () => {
+            let enumInfo;
+
+            before(() => {
+                const field = { enumName: 'fieldName', fieldValues: 'AAA, BBB' };
+                enumInfo = utils.getEnumInfo(field);
+            });
+
+            it('returns an empty string for the clientRootFolder property', () => {
+                assert.strictEqual(enumInfo.clientRootFolder, '');
+            });
+        });
+        describe('when passing a client root folder', () => {
+            let enumInfo;
+
+            before(() => {
+                const field = { enumName: 'fieldName', fieldValues: 'AAA, BBB' };
+                const clientRootFolder = 'root';
+                enumInfo = utils.getEnumInfo(field, clientRootFolder);
+            });
+
+            it('returns the clientRootFolder property suffixed by a dash', () => {
+                assert.strictEqual(enumInfo.clientRootFolder, 'root-');
+            });
         });
     });
     describe('::deepFind function', () => {