Repository: jhipster/generator-jhipster (ts)

Issue:
No translation for min and max validation errors
From https://github.com/mraible/21-points/issues/33



Pull request:
handle missing translations for min and max validations
Fix #7305

 - Maps Min/Max/DecimalMin/DecimalMax to the Size i18n key on the client.  
 - Adds test for `alert-error.component.ts` 

Please make sure the below checklist is followed for Pull Requests.

- [x] [Travis tests](https://travis-ci.org/jhipster/generator-jhipster/pull_requests) are green
- [x] Tests are added where necessary
- [x] Documentation is added/updated where necessary
- [x] Coding Rules & Commit Guidelines as per our [CONTRIBUTING.md document](https://github.com/jhipster/generator-jhipster/blob/master/CONTRIBUTING.md) are followed

<!--
Please also reference the issue number in a commit message to [automatically close the related Github issue](https://help.github.com/articles/closing-issues-via-commit-messages/)

Note: It is also possible to add `[skip ci]` to your commit message to skip Travis tests
-->


Patch:
diff --git a/generators/client/files-angular.js b/generators/client/files-angular.js
index ac66e80f4a..c21f56cb95 100644
--- a/generators/client/files-angular.js
+++ b/generators/client/files-angular.js
@@ -468,7 +468,8 @@ const files = {
                 'spec/helpers/mock-login.service.ts',
                 'spec/helpers/mock-event-manager.service.ts',
                 'spec/helpers/mock-active-modal.service.ts',
-                'spec/helpers/mock-state-storage.service.ts'
+                'spec/helpers/mock-state-storage.service.ts',
+                'spec/helpers/mock-alert.service.ts'
             ]
         },
         {
@@ -483,7 +484,8 @@ const files = {
                 'spec/app/account/register/register.component.spec.ts',
                 'spec/app/account/settings/settings.component.spec.ts',
                 // login component tests
-                'spec/app/shared/login/login.component.spec.ts'
+                'spec/app/shared/login/login.component.spec.ts',
+                'spec/app/shared/alert/alert-error.component.spec.ts'
             ]
         },
         {
diff --git a/generators/client/templates/angular/src/main/webapp/app/shared/alert/alert-error.component.ts.ejs b/generators/client/templates/angular/src/main/webapp/app/shared/alert/alert-error.component.ts.ejs
index 3ee608f830..3d0ed3023c 100644
--- a/generators/client/templates/angular/src/main/webapp/app/shared/alert/alert-error.component.ts.ejs
+++ b/generators/client/templates/angular/src/main/webapp/app/shared/alert/alert-error.component.ts.ejs
@@ -70,6 +70,9 @@ export class <%=jhiPrefixCapitalized%>AlertErrorComponent implements OnDestroy {
                         const fieldErrors = httpErrorResponse.error.fieldErrors;
                         for (i = 0; i < fieldErrors.length; i++) {
                             const fieldError = fieldErrors[i];
+                            if (['Min', 'Max', 'DecimalMin', 'DecimalMax'].includes(fieldError.message)) {
+                                fieldError.message = 'Size';
+                            }
                             // convert 'something[14].other[4].id' to 'something[].other[].id' so translations can be written to it
                             const convertedField = fieldError.field.replace(/\[\d*\]/g, '[]');
                             const fieldName = <% if (enableTranslation) { %>translateService.instant('<%=angularAppName%>.' +
diff --git a/generators/client/templates/angular/src/main/webapp/swagger-ui/index.html.ejs b/generators/client/templates/angular/src/main/webapp/swagger-ui/index.html.ejs
index beb24e0d8c..6900e5e333 100644
--- a/generators/client/templates/angular/src/main/webapp/swagger-ui/index.html.ejs
+++ b/generators/client/templates/angular/src/main/webapp/swagger-ui/index.html.ejs
@@ -38,6 +38,7 @@
     <script src='./dist/lib/backbone-min.js' type='text/javascript'></script>
     <script src='./dist/swagger-ui.min.js' type='text/javascript'></script>
     <script src='./dist/lib/highlight.9.1.0.pack.js' type='text/javascript'></script>
+    <script src='./dist/lib/highlight.9.1.0.pack.js' type='text/javascript'></script>
     <script src='./dist/lib/jsoneditor.min.js' type='text/javascript'></script>
     <script src='./dist/lib/marked.js' type='text/javascript'></script>
     <script src='./dist/lib/swagger-oauth.js' type='text/javascript'></script>
@@ -100,9 +101,20 @@
                 });
 
                 function addApiKeyAuthorization() {
-                <%_ if (authenticationType === 'session' || authenticationType === 'oauth2' || authenticationType === 'uaa') { _%>
+                <%_ if (authenticationType === 'session' || authenticationType === 'oauth2') { _%>
                     var apiKeyAuth = new SwaggerClient.ApiKeyAuthorization("X-XSRF-TOKEN", getCSRF(), "header");
                     window.swaggerUi.api.clientAuthorizations.add("key", apiKeyAuth);
+                <%_ } else if (authenticationType === 'uaa') { _%>
+                    var interceptor = {
+                        requestInterceptor: {
+                            apply: function (requestObj) {
+                                var headers = requestObj.headers || {};
+                                headers['X-XSRF-TOKEN'] = getCSRF();
+                                return requestObj;
+                            }
+                        }
+                    };
+                    window.swaggerUi.options.requestInterceptor = interceptor.requestInterceptor
                 <%_ } else if (authenticationType === 'jwt') { _%>
                     var authToken = JSON.parse(localStorage.getItem("<%=jhiPrefixDashed %>-authenticationtoken") || sessionStorage.getItem("<%=jhiPrefixDashed %>-authenticationtoken"));
                     var apiKeyAuth = new SwaggerClient.ApiKeyAuthorization("Authorization", "Bearer " + authToken, "header");
@@ -110,18 +122,16 @@
                 <%_ } _%>
                 }
 
-                <%_ if (authenticationType === 'session' || authenticationType === 'oauth2' || authenticationType === 'uaa') { _%>
                 function getCSRF() {
                     var name = "XSRF-TOKEN=";
                     var ca = document.cookie.split(';');
                     for(var i=0; i<ca.length; i++) {
                         var c = ca[i];
-                        while (c.charAt(0) === ' ') c = c.substring(1);
+                        while (c.charAt(0)==' ') c = c.substring(1);
                         if (c.indexOf(name) !== -1) return c.substring(name.length,c.length);
                     }
                     return "";
                 }
-                <%_ } _%>
 
                 function log() {
                     if ('console' in window) {
diff --git a/generators/client/templates/react/src/main/webapp/app/config/notification-middleware.ts.ejs b/generators/client/templates/react/src/main/webapp/app/config/notification-middleware.ts.ejs
index 9f2849ffe1..80b45178d0 100644
--- a/generators/client/templates/react/src/main/webapp/app/config/notification-middleware.ts.ejs
+++ b/generators/client/templates/react/src/main/webapp/app/config/notification-middleware.ts.ejs
@@ -101,6 +101,9 @@ export default () => next => action => {
                 const fieldErrors = data.fieldErrors;
                 for (i = 0; i < fieldErrors.length; i++) {
                   const fieldError = fieldErrors[i];
+                  if (['Min', 'Max', 'DecimalMin', 'DecimalMax'].includes(fieldError.message)) {
+                      fieldError.message = 'Size';
+                  }
                   // convert 'something[14].other[4].id' to 'something[].other[].id' so translations can be written to it
                   const convertedField = fieldError.field.replace(/\[\d*\]/g, '[]');
                   const fieldName = <% if (enableTranslation) { %>translate(
diff --git a/generators/client/templates/react/src/main/webapp/swagger-ui/index.html.ejs b/generators/client/templates/react/src/main/webapp/swagger-ui/index.html.ejs
index 70029e3634..99e26b8de8 100644
--- a/generators/client/templates/react/src/main/webapp/swagger-ui/index.html.ejs
+++ b/generators/client/templates/react/src/main/webapp/swagger-ui/index.html.ejs
@@ -100,7 +100,7 @@
                 });
 
                 function addApiKeyAuthorization() {
-                <%_ if (authenticationType === 'session' || authenticationType === 'uaa') { _%>
+                <%_ if (authenticationType === 'session') { _%>
                     var apiKeyAuth = new SwaggerClient.ApiKeyAuthorization("X-XSRF-TOKEN", getCSRF(), "header");
                     window.swaggerUi.api.clientAuthorizations.add("key", apiKeyAuth);
                 <%_ } else if (authenticationType === 'oauth2') { _%>
@@ -108,25 +108,23 @@
                     var apiKeyAuth = new SwaggerClient.ApiKeyAuthorization("Authorization",
                             "Bearer " + authToken, "header");
                     window.swaggerUi.api.clientAuthorizations.add("key", apiKeyAuth);
-                <%_ } else if (authenticationType === 'jwt') { _%>
+                <%_ } else if (authenticationType === 'jwt' || authenticationType === 'uaa') { _%>
                     var authToken = JSON.parse(localStorage.getItem("jhi-authenticationToken") || sessionStorage.getItem("jhi-authenticationToken"));
                     var apiKeyAuth = new SwaggerClient.ApiKeyAuthorization("Authorization", "Bearer " + authToken, "header");
                     window.swaggerUi.api.clientAuthorizations.add("bearer", apiKeyAuth);
                 <%_ } _%>
                 }
 
-                <%_ if (authenticationType === 'session' || authenticationType === 'oauth2' || authenticationType === 'uaa') { _%>
                 function getCSRF() {
                     var name = "XSRF-TOKEN=";
                     var ca = document.cookie.split(';');
                     for(var i=0; i<ca.length; i++) {
                         var c = ca[i];
-                        while (c.charAt(0)===' ') c = c.substring(1);
-                        if (c.indexOf(name) !== -1) return c.substring(name.length,c.length);
+                        while (c.charAt(0)==' ') c = c.substring(1);
+                        if (c.indexOf(name) != -1) return c.substring(name.length,c.length);
                     }
                     return "";
                 }
-                <%_ } _%>
 
                 function log() {
                     if ('console' in window) {
@@ -145,7 +143,7 @@
                     var security = {};
                     window.springfox.securityConfig(function(data) {
                         security = data;
-                        if (typeof initOAuth === "function" && oAuthIsDefined(security)) {
+                        if (typeof initOAuth == "function" && oAuthIsDefined(security)) {
                             initOAuth(security);
                         }
                     });
diff --git a/generators/generator-base.js b/generators/generator-base.js
index 6b79999326..ce204f2176 100644
--- a/generators/generator-base.js
+++ b/generators/generator-base.js
@@ -2181,13 +2181,13 @@ module.exports = class extends PrivateBase {
             name: 'baseName',
             validate: (input) => {
                 if (!(/^([a-zA-Z0-9_]*)$/.test(input))) {
-                    return 'Your base name cannot contain special characters or a blank space';
+                    return 'Your application name cannot contain special characters or a blank space';
                 }
-                if ((generator.applicationType === 'microservice' || generator.applicationType === 'uaa') && /_/.test(input)) {
-                    return 'Your base name cannot contain underscores as this does not meet the URI spec';
+                if (generator.applicationType === 'microservice' && /_/.test(input)) {
+                    return 'Your microservice name cannot contain underscores as this does not meet the URI spec';
                 }
                 if (input === 'application') {
-                    return 'Your base name cannot be named \'application\' as this is a reserved name for Spring Boot';
+                    return 'Your application name cannot be named \'application\' as this is a reserved name for Spring Boot';
                 }
                 return true;
             },
diff --git a/generators/server/templates/pom.xml.ejs b/generators/server/templates/pom.xml.ejs
index ad58476db2..dadc6267f4 100644
--- a/generators/server/templates/pom.xml.ejs
+++ b/generators/server/templates/pom.xml.ejs
@@ -111,7 +111,7 @@
 
         <!-- Sonar properties -->
         <sonar.exclusions><%= CLIENT_MAIN_SRC_DIR %>content/**/*.*, <%= CLIENT_MAIN_SRC_DIR %>i18n/*.js, <%= CLIENT_DIST_DIR %>**/*.*</sonar.exclusions>
-        <sonar.issue.ignore.multicriteria>S3437,<% if (authenticationType === 'jwt') { %>S4502,<% } %>S4684,UndocumentedApi,BoldAndItalicTagsCheck</sonar.issue.ignore.multicriteria>
+        <sonar.issue.ignore.multicriteria>S3437,S4684,UndocumentedApi,BoldAndItalicTagsCheck</sonar.issue.ignore.multicriteria>
         <!-- Rule https://sonarcloud.io/coding_rules?open=Web%3ABoldAndItalicTagsCheck&rule_key=Web%3ABoldAndItalicTagsCheck is ignored. Even if we agree that using the "i" tag is an awful practice, this is what is recommended by http://fontawesome.io/examples/ -->
         <sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.resourceKey><%= CLIENT_MAIN_SRC_DIR %>app/**/*.*</sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.resourceKey>
         <sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.ruleKey>Web:BoldAndItalicTagsCheck</sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.ruleKey>
@@ -121,11 +121,6 @@
         <!-- Rule https://sonarcloud.io/coding_rules?open=squid%3AUndocumentedApi&rule_key=squid%3AUndocumentedApi is ignored, as we want to follow "clean code" guidelines and classes, methods and arguments names should be self-explanatory -->
         <sonar.issue.ignore.multicriteria.UndocumentedApi.resourceKey><%= MAIN_DIR %>java/**/*</sonar.issue.ignore.multicriteria.UndocumentedApi.resourceKey>
         <sonar.issue.ignore.multicriteria.UndocumentedApi.ruleKey>squid:UndocumentedApi</sonar.issue.ignore.multicriteria.UndocumentedApi.ruleKey>
-        <%_ if (authenticationType === 'jwt') { _%>
-        <!-- Rule https://sonarcloud.io/coding_rules?open=squid%3AS4502&rule_key=squid%3AS4502 is ignored, as for JWT tokens we are not subject to CSRF attack -->
-        <sonar.issue.ignore.multicriteria.S4502.resourceKey>src/main/java/**/*</sonar.issue.ignore.multicriteria.S4502.resourceKey>
-        <sonar.issue.ignore.multicriteria.S4502.ruleKey>squid:S4502</sonar.issue.ignore.multicriteria.S4502.ruleKey>
-        <%_ } _%>
         <!-- Rule https://sonarcloud.io/coding_rules?open=squid%3AS4684&rule_key=squid%3AS4684 -->
         <sonar.issue.ignore.multicriteria.S4684.resourceKey>src/main/java/**/*</sonar.issue.ignore.multicriteria.S4684.resourceKey>
         <sonar.issue.ignore.multicriteria.S4684.ruleKey>squid:S4684</sonar.issue.ignore.multicriteria.S4684.ruleKey>


Test patch:
diff --git a/generators/client/templates/angular/src/test/javascript/spec/app/shared/alert/alert-error.component.spec.ts.ejs b/generators/client/templates/angular/src/test/javascript/spec/app/shared/alert/alert-error.component.spec.ts.ejs
new file mode 100644
index 0000000000..e21ed7363b
--- /dev/null
+++ b/generators/client/templates/angular/src/test/javascript/spec/app/shared/alert/alert-error.component.spec.ts.ejs
@@ -0,0 +1,137 @@
+import { ComponentFixture, TestBed, async, inject, fakeAsync, tick } from '@angular/core/testing';
+import { HttpErrorResponse, HttpHeaders } from '@angular/common/http';
+import { JhiAlertService, JhiEventManager } from 'ng-jhipster';
+<%_ if (enableTranslation) { _%>
+import { TranslateModule } from '@ngx-translate/core';
+<%_ } _%>
+
+import { <%=angularXAppName%>TestModule } from '../../../test.module';
+import { <%=jhiPrefixCapitalized%>AlertErrorComponent } from 'app/shared/alert/alert-error.component';
+import { MockAlertService } from "../../../helpers/mock-alert.service";
+
+describe('Component Tests', () => {
+    describe('Alert Error Component', () => {
+        let comp: <%=jhiPrefixCapitalized%>AlertErrorComponent;
+        let fixture: ComponentFixture<<%=jhiPrefixCapitalized%>AlertErrorComponent>;
+        let eventManager: JhiEventManager;
+
+        beforeEach(async(() => {
+            TestBed.configureTestingModule({
+                imports: [<%=angularXAppName%>TestModule<% if (enableTranslation) { %>, TranslateModule.forRoot()<% } %>],
+                declarations: [<%=jhiPrefixCapitalized%>AlertErrorComponent],
+                providers: [
+                    JhiEventManager,
+                    {
+                        provide: JhiAlertService,
+                        useClass: MockAlertService
+                    }
+                ]
+            })
+                .overrideTemplate(<%=jhiPrefixCapitalized%>AlertErrorComponent, '')
+                .compileComponents();
+        }));
+
+        beforeEach(() => {
+            fixture = TestBed.createComponent(<%=jhiPrefixCapitalized%>AlertErrorComponent);
+            comp = fixture.componentInstance;
+            eventManager = fixture.debugElement.injector.get(JhiEventManager);
+        });
+
+        describe('Error Handling', () => {
+            it('Should display an alert on status 0', () => {
+                // GIVEN
+                eventManager.broadcast({name: '<%=angularAppName%>.httpError', content: {status: 0}});
+                // THEN
+                expect(comp.alerts.length).toBe(1);
+                expect(comp.alerts[0].msg).toBe(<% if (enableTranslation) { %>'error.server.not.reachable'<% } else { %>'Server not reachable'<% } %>);
+            });
+            it('Should display an alert on status 404', () => {
+                // GIVEN
+                eventManager.broadcast({name: '<%=angularAppName%>.httpError', content: {status: 404}});
+                // THEN
+                expect(comp.alerts.length).toBe(1);
+                expect(comp.alerts[0].msg).toBe(<% if (enableTranslation) { %>'error.url.not.found'<% } else { %>'Not found'<% } %>);
+            });
+            it('Should display an alert on generic error', () => {
+                // GIVEN
+                eventManager.broadcast({name: '<%=angularAppName%>.httpError', content: {error: {message: "Error Message"}}});
+                eventManager.broadcast({name: '<%=angularAppName%>.httpError', content: {error: "Second Error Message"}});
+                // THEN
+                expect(comp.alerts.length).toBe(2);
+                expect(comp.alerts[0].msg).toBe('Error Message');
+                expect(comp.alerts[1].msg).toBe('Second Error Message');
+            });
+           it('Should display an alert on status 400 for generic error', () => {
+                // GIVEN
+                const response = new HttpErrorResponse({
+                   url: "http://localhost:8080/api/foos",
+                   headers: new HttpHeaders(),
+                   status: 400,
+                   statusText: 'Bad Request',
+                   error: {
+                       "type":"https://www.jhipster.tech/problem/constraint-violation",
+                       "title":"Bad Request",
+                       "status":400,
+                       "path":"/api/foos",
+                       "message":"error.validation"
+                   }
+                });
+                eventManager.broadcast({name: '<%=angularAppName%>.httpError', content: response});
+                // THEN
+                expect(comp.alerts.length).toBe(1);
+                expect(comp.alerts[0].msg).toBe('error.validation');
+            });
+           it('Should display an alert on status 400 for generic error without message', () => {
+                // GIVEN
+                const response = new HttpErrorResponse({
+                   url: "http://localhost:8080/api/foos",
+                   headers: new HttpHeaders(),
+                   status: 400,
+                   error: "Bad Request"
+                });
+                eventManager.broadcast({name: '<%=angularAppName%>.httpError', content: response});
+                // THEN
+                expect(comp.alerts.length).toBe(1);
+                expect(comp.alerts[0].msg).toBe('Bad Request');
+            });
+            it('Should display an alert on status 400 for invalid parameters', () => {
+                // GIVEN
+                const response = new HttpErrorResponse({
+                    url: "http://localhost:8080/api/foos",
+                    headers: new HttpHeaders(),
+                    status: 400,
+                    statusText: 'Bad Request',
+                    error: {
+                        "type":"https://www.jhipster.tech/problem/constraint-violation",
+                        "title":"Method argument not valid",
+                        "status":400,
+                        "path":"/api/foos",
+                        "message":"error.validation",
+                        "fieldErrors":[{"objectName":"foo","field":"minField","message":"Min"}]
+                    }
+                });
+                eventManager.broadcast({name: '<%=angularAppName%>.httpError', content: response});
+                // THEN
+                expect(comp.alerts.length).toBe(1);
+                expect(comp.alerts[0].msg).toBe(<% if (enableTranslation) { %>'error.Size'<% } else { %>'Error on field "MinField"'<% } %>);
+            });
+            it('Should display an alert on status 400 for error headers', () => {
+                // GIVEN
+                const response = new HttpErrorResponse({
+                    url: "http://localhost:8080/api/foos",
+                    headers: new HttpHeaders().append("app-error", "Error Message").append("app-params", "foo"),
+                    status: 400,
+                    statusText: 'Bad Request',
+                    error: {
+                        "status":400,
+                        "message":"error.validation",
+                    }
+                });
+                eventManager.broadcast({name: '<%=angularAppName%>.httpError', content: response});
+                // THEN
+                expect(comp.alerts.length).toBe(1);
+                expect(comp.alerts[0].msg).toBe('Error Message');
+            });
+        });
+    });
+});
diff --git a/generators/client/templates/angular/src/test/javascript/spec/helpers/mock-alert.service.ts.ejs b/generators/client/templates/angular/src/test/javascript/spec/helpers/mock-alert.service.ts.ejs
new file mode 100644
index 0000000000..9cf4dce6fa
--- /dev/null
+++ b/generators/client/templates/angular/src/test/javascript/spec/helpers/mock-alert.service.ts.ejs
@@ -0,0 +1,12 @@
+import { SpyObject } from './spyobject';
+import { JhiAlertService, JhiAlert } from 'ng-jhipster';
+
+export class MockAlertService extends SpyObject {
+
+    constructor() {
+        super(JhiAlertService);
+    }
+    addAlert(alertOptions: JhiAlert) {
+        return alertOptions;
+    }
+}
diff --git a/generators/client/templates/react/src/test/javascript/spec/app/config/notification-middleware.spec.ts.ejs b/generators/client/templates/react/src/test/javascript/spec/app/config/notification-middleware.spec.ts.ejs
index 2a11efaf8b..f12f829056 100644
--- a/generators/client/templates/react/src/test/javascript/spec/app/config/notification-middleware.spec.ts.ejs
+++ b/generators/client/templates/react/src/test/javascript/spec/app/config/notification-middleware.spec.ts.ejs
@@ -48,6 +48,14 @@ describe('Notification Middleware', () => {
     },
     payload: Promise.resolve('foo')
   };
+  const HEADER_SUCCESS = {
+    type: SUCCESS_TYPE,
+    payload: Promise.resolve({
+        "status": 201,
+        "statusText": "Created",
+        "headers": {"app-alert": "foo.created", "app-params": "foo"}
+    })
+  };
   const DEFAULT_ERROR = {
     type: ERROR_TYPE,
     meta: {
@@ -55,6 +63,63 @@ describe('Notification Middleware', () => {
     },
     payload: Promise.reject(new Error('foo'))
   };
+  const VALIDATION_ERROR = {
+    type: ERROR_TYPE,
+    payload: Promise.reject({
+      "response": {
+        "data": {
+          "type": "https://www.jhipster.tech/problem/constraint-violation",
+          "title": "Method argument not valid",
+          "status": 400,
+          "path": "/api/foos",
+          "message": "error.validation",
+          "fieldErrors": [ { "objectName": "foos", "field": "minField", "message": "Min" } ] },
+        "status": 400,
+        "statusText": "Bad Request",
+        "headers": { "expires": "0" }
+      }
+    })
+  };
+  const HEADER_ERRORS = {
+    type: ERROR_TYPE,
+    payload: Promise.reject({
+      "response": {
+        "status": 400,
+        "statusText": "Bad Request",
+        "headers": { "app-error": "foo.creation", "app-params": "foo" }
+      }
+    })
+  };
+  const NOT_FOUND_ERROR = {
+    type: ERROR_TYPE,
+    payload: Promise.reject({
+      "response": {
+        "data": {
+          "status": 404,
+          "message": "Not found",
+        },
+        "status": 404
+      }
+    })
+  };
+  const NO_SERVER_ERROR = {
+    type: ERROR_TYPE,
+    payload: Promise.reject({
+      "response": {
+        "status": 0
+      }
+    })
+  };
+  const GENERIC_ERROR = {
+    type: ERROR_TYPE,
+    payload: Promise.reject({
+      "response": {
+        data: {
+          message: "Error"
+        }
+      }
+    })
+  };
 
   const makeStore = () => applyMiddleware(notificationMiddleware, promiseMiddleware())(createStore)(() => null);
 
@@ -90,6 +155,13 @@ describe('Notification Middleware', () => {
     const toastMsg = (toastify.toast as any).success.getCall(0).args[0];
     expect(toastMsg).toEqual(DEFAULT_SUCCESS_MESSAGE);
   });
+  it('should trigger a success toast message and return promise success for header alerts', async () => {
+    await store.dispatch(HEADER_SUCCESS).then(resp => {
+      expect(resp.value.status).toEqual(201);
+    });
+    const toastMsg = (toastify.toast as any).success.getCall(0).args[0];
+    expect(toastMsg).toContain('foo.created');
+  });
 
   it('should trigger an error toast message and return promise error', async () => {
     await store.dispatch(DEFAULT_ERROR).catch(err => {
@@ -98,4 +170,39 @@ describe('Notification Middleware', () => {
     const toastMsg = (toastify.toast as any).error.getCall(0).args[0];
     expect(toastMsg).toEqual(DEFAULT_ERROR_MESSAGE);
   });
+  it('should trigger an error toast message and return promise error for generic message', async () => {
+    await store.dispatch(GENERIC_ERROR).catch(err => {
+      expect(err.response.data.message).toEqual('Error');
+    });
+    const toastMsg = (toastify.toast as any).error.getCall(0).args[0];
+    expect(toastMsg).toContain('Error');
+  });
+  it('should trigger an error toast message and return promise error for 400 response code', async () => {
+    await store.dispatch(VALIDATION_ERROR).catch(err => {
+      expect(err.response.data.message).toEqual('error.validation');
+    });
+    const toastMsg = (toastify.toast as any).error.getCall(0).args[0];
+    expect(toastMsg).toContain(<% if (enableTranslation) { %>'error.Size'<% } else { %>'Error on field "MinField"'<% } %>);
+  });
+  it('should trigger an error toast message and return promise error for 404 response code', async () => {
+    await store.dispatch(NOT_FOUND_ERROR).catch(err => {
+      expect(err.response.data.message).toEqual('Not found');
+    });
+    const toastMsg = (toastify.toast as any).error.getCall(0).args[0];
+    expect(toastMsg).toContain(<% if (enableTranslation) { %>'error.url.not.found'<% } else { %>'Not found'<% } %>);
+  });
+  it('should trigger an error toast message and return promise error for 0 response code', async () => {
+    await store.dispatch(NO_SERVER_ERROR).catch(err => {
+      expect(err.response.status).toEqual(0);
+    });
+    const toastMsg = (toastify.toast as any).error.getCall(0).args[0];
+    expect(toastMsg).toContain(<% if (enableTranslation) { %>'error.server.not.reachable'<% } else { %>'Server not reachable'<% } %>);
+  });
+  it('should trigger an error toast message and return promise error for headers containing errors', async () => {
+    await store.dispatch(HEADER_ERRORS).catch(err => {
+      expect(err.response.status).toEqual(400);
+    });
+    const toastMsg = (toastify.toast as any).error.getCall(0).args[0];
+    expect(toastMsg).toContain('foo.creation');
+  });
 });
diff --git a/test/utils/expected-files.js b/test/utils/expected-files.js
index a3439d8234..f97e9c43c3 100644
--- a/test/utils/expected-files.js
+++ b/test/utils/expected-files.js
@@ -355,9 +355,11 @@ const expectedFiles = {
         `${CLIENT_TEST_SRC_DIR}spec/app/admin/audits/audits.component.spec.ts`,
         `${CLIENT_TEST_SRC_DIR}spec/app/admin/audits/audits.service.spec.ts`,
         `${CLIENT_TEST_SRC_DIR}spec/app/admin/health/health.component.spec.ts`,
+        `${CLIENT_TEST_SRC_DIR}spec/app/shared/alert/alert-error.component.spec.ts`,
         `${CLIENT_TEST_SRC_DIR}spec/app/shared/login/login.component.spec.ts`,
         `${CLIENT_TEST_SRC_DIR}spec/helpers/mock-account.service.ts`,
         `${CLIENT_TEST_SRC_DIR}spec/helpers/mock-active-modal.service.ts`,
+        `${CLIENT_TEST_SRC_DIR}spec/helpers/mock-alert.service.ts`,
         `${CLIENT_TEST_SRC_DIR}spec/helpers/mock-event-manager.service.ts`,
         `${CLIENT_TEST_SRC_DIR}spec/helpers/mock-language.service.ts`,
         `${CLIENT_TEST_SRC_DIR}spec/helpers/mock-login.service.ts`,