METRON-2208 [UI] Increase unit test coverage for Alert Details (sardell) closes apache/metron#1479
diff --git a/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.html b/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.html
index 4c8431a..c4b640f 100644
--- a/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.html
+++ b/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.html
@@ -60,6 +60,7 @@
                                             #metaAlertNameInput
                                             type="text"
                                             class="form-control"
+                                            data-qe-id="meta-alert-name-input"
                                             [value]="alertSource.name"
                                             [(ngModel)]="alertName"
                                             (keyup)="onSaveNameInputKeyPress($event)"
@@ -68,10 +69,11 @@
                                             class="input-group-addon"
                                             [ngClass]="{ disabled: isSaveNameButtonDisabled() }"
                                             (click)="saveName()"
+                                            data-qe-id="save-name-input"
                                         >
                                             <i class="fa fa-check" aria-hidden="true"></i>
                                         </span>
-                                        <span class="input-group-addon" (click)="onSaveNameInputCancel()">
+                                        <span class="input-group-addon" data-qe-id="cancel-name-input" (click)="onSaveNameInputCancel()">
                                             <i class="fa fa-times" aria-hidden="true"></i>
                                         </span>
                                     </div>
@@ -120,7 +122,7 @@
                         <div *ngIf="activeTab === tabs.COMMENTS" class="mx-3 my-3">
                             <div> Comments <span *ngIf="alertCommentsWrapper.length > 0"> ({{alertCommentsWrapper.length}}) </span></div>
                             <textarea class="form-control" [(ngModel)]="alertCommentStr"> </textarea>
-                            <button class="btn btn-mine_shaft_2" [disabled]="alertCommentStr.trim().length === 0" (click)="onAddComment()">ADD COMMENT</button>
+                            <button class="btn btn-mine_shaft_2" data-qe-id="add-comment-button" [disabled]="alertCommentStr.trim().length === 0" (click)="onAddComment()">ADD COMMENT</button>
                             <ng-container *ngFor="let alertCommentWrapper of alertCommentsWrapper; let i = index">
                                 <div class="comment-container" data-qe-id="comment">
                                     <i
diff --git a/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.spec.ts b/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.spec.ts
index 92843e3..9b0487a 100644
--- a/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.spec.ts
+++ b/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.spec.ts
@@ -15,7 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { async, ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
+import { async, ComponentFixture, TestBed, fakeAsync, tick, flush } from '@angular/core/testing';
 
 import { AlertDetailsComponent, AlertCommentWrapper } from './alert-details.component';
 import { SharedModule } from 'app/shared/shared.module';
@@ -35,9 +35,10 @@
 import { AlertComment } from './alert-comment';
 import { Subject } from 'rxjs';
 import { ConfirmationType } from 'app/model/confirmation-type';
-import {CommentAddRemoveRequest} from "../../model/comment-add-remove-request";
-import {AlertSource} from "../../model/alert-source";
-import {of} from "rxjs/index";
+import { CommentAddRemoveRequest } from '../../model/comment-add-remove-request';
+import { AlertSource } from '../../model/alert-source';
+import { of } from 'rxjs/index';
+import { Router } from '@angular/router';
 
 const alertDetail = {
   'enrichments:geo:ip_dst_addr:locID': '5308655',
@@ -90,6 +91,8 @@
   let component: AlertDetailsComponent;
   let fixture: ComponentFixture<AlertDetailsComponent>;
   let updateService: UpdateService;
+  let router: Router;
+  let alertsService: AlertsService;
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
@@ -102,7 +105,6 @@
       providers: [
         SearchService,
         AuthenticationService,
-        AlertsService,
         UpdateService,
         { provide: GlobalConfigService, useValue: {
           get: () => { return of({})}
@@ -128,15 +130,22 @@
           provide: DataSource,
           useClass: ElasticSearchLocalstorageImpl
         },
+        { provide: AlertsService,
+          useValue: {
+            escalate: () => {}
+          }
+        },
       ],
     })
     .compileComponents();
+    alertsService = TestBed.get(AlertsService);
   }));
 
   beforeEach(() => {
     fixture = TestBed.createComponent(AlertDetailsComponent);
     component = fixture.componentInstance;
     updateService = fixture.debugElement.injector.get(UpdateService);
+    router = TestBed.get(Router)
     fixture.detectChanges();
   });
 
@@ -198,4 +207,152 @@
     expect(setAlertSpy).toHaveBeenCalledWith(expectedAlertSource);
     expect(setAlertSpy).toHaveBeenCalledTimes(1);
   }));
+
+  it('should return to alert list page when goBack() is called', () => {
+    let navigateSpy = spyOn(router, 'navigateByUrl');
+    component.goBack();
+    expect(navigateSpy).toHaveBeenCalledWith('/alerts-list');
+  });
+
+  it('should set alert source with setAlert', () => {
+    const alertSource = {
+      name: 'test',
+      comments: ['test comment 1', 'test comment 2'],
+      metron_alert: ''
+    };
+    component.setAlert(alertSource);
+    expect(component.alertName).toBe('test');
+    expect(component.alertSource).toBe(alertSource);
+
+    alertSource.metron_alert = 'test alert';
+    component.setAlert(alertSource);
+    expect(component.alertSources).toBe(alertSource.metron_alert);
+  });
+
+  it('should return the correct alert state with getAlertState', () => {
+    expect(component.getAlertState('OPEN')).toBe(component.alertState.OPEN);
+    expect(component.getAlertState('ESCALATE')).toBe(
+      component.alertState.ESCALATE
+    );
+    expect(component.getAlertState('DISMISS')).toBe(
+      component.alertState.DISMISS
+    );
+    expect(component.getAlertState('RESOLVE')).toBe(
+      component.alertState.RESOLVE
+    );
+    expect(component.getAlertState('NEW')).toBe(component.alertState.NEW);
+  });
+
+  it('should update alert state', () => {
+    spyOn(alertsService, 'escalate').and.returnValue(of({}));
+    spyOn(component, 'updateAlertState').and.callThrough();
+
+    component.alertSource = new AlertSource();
+    component.processEscalate();
+    expect(component.updateAlertState).toHaveBeenCalledWith('ESCALATE');
+
+    component.processOpen();
+    expect(component.updateAlertState).toHaveBeenCalledWith('OPEN');
+
+    component.processNew();
+    expect(component.updateAlertState).toHaveBeenCalledWith('NEW');
+
+    component.processDismiss();
+    expect(component.updateAlertState).toHaveBeenCalledWith('DISMISS');
+
+    component.processResolve();
+    expect(component.updateAlertState).toHaveBeenCalledWith('RESOLVE');
+  });
+
+  it('should toggle editor with toggleNameEditor', fakeAsync(() => {
+    expect(component.showEditor).toBe(false);
+    component.alertSources = ['test1', 'test2'];
+    component.toggleNameEditor();
+    fixture.detectChanges();
+
+    const focus = spyOn(component.metaAlertNameInput.nativeElement, 'focus');
+    expect(component.showEditor).toBe(true);
+    tick(500);
+    fixture.detectChanges();
+    expect(focus).toHaveBeenCalled();
+
+    component.alertSources = [];
+    component.toggleNameEditor();
+    fixture.detectChanges();
+    expect(component.showEditor).toBe(true);
+    flush();
+  }));
+
+  it('should send a request to update an alert name with saveName', () => {
+    const responseMock = new AlertSource();
+    const patchSpy = spyOn(updateService, 'patch').and.returnValue(
+      of(responseMock)
+    );
+    component.alertName = 'test name';
+    component.alertId = '123';
+    fixture.detectChanges();
+
+    component.saveName();
+    expect(patchSpy).toHaveBeenCalled();
+  });
+
+  it('should send a request to add a comment with onAddComment', () => {
+    const addCommentSpy = spyOn(updateService, 'addComment').and.returnValue(
+      of()
+    );
+    component.alertSources = ['test'];
+    component.activeTab = component.tabs.COMMENTS;
+    component.alertCommentStr = 'abcd';
+    fixture.detectChanges();
+
+    const addCommentBtn = fixture.debugElement.query(
+      By.css('[data-qe-id="add-comment-button"]')
+    );
+    addCommentBtn.nativeElement.click();
+    expect(addCommentSpy).toHaveBeenCalled();
+  });
+
+  it('should update a meta alert name or escape the input based on certain keyup events', () => {
+    component.alertSources = ['test1', 'test2'];
+    component.toggleNameEditor();
+    component.alertSource.name = 'test';
+    fixture.detectChanges();
+    const saveNameSpy = spyOn(component, 'saveName');
+    const toggleSpy = spyOn(component, 'toggleNameEditor');
+
+    const metaAlertNameInput = fixture.debugElement.query(
+      By.css('[data-qe-id="meta-alert-name-input"')
+    );
+    const enterEvent = new KeyboardEvent('keyup', {
+      code: 'Enter'
+    });
+    const escEvent = new KeyboardEvent('keyup', {
+      code: 'Escape'
+    });
+
+    metaAlertNameInput.nativeElement.value = 'test';
+    metaAlertNameInput.nativeElement.dispatchEvent(enterEvent);
+    expect(saveNameSpy).toHaveBeenCalled();
+
+    metaAlertNameInput.nativeElement.value = 'test';
+    metaAlertNameInput.nativeElement.dispatchEvent(escEvent);
+    expect(component.alertName).toBe(component.alertSource.name);
+    expect(toggleSpy).toHaveBeenCalled();
+  });
+
+  it('should restore the alert name if cancel is clicked', () => {
+    component.alertSources = ['test1', 'test2'];
+    component.toggleNameEditor();
+    component.alertSource.name = 'test';
+    fixture.detectChanges();
+    const toggleSpy = spyOn(component, 'toggleNameEditor');
+    const cancelInputBtn = fixture.debugElement.query(
+      By.css('[data-qe-id="cancel-name-input"]')
+    );
+    cancelInputBtn.nativeElement.click();
+
+    expect(component.alertName).toBe(component.alertSource.name);
+    expect(toggleSpy).toHaveBeenCalled();
+  });
+
 });
diff --git a/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts b/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts
index c5bb3ba..2e5a64d 100644
--- a/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts
+++ b/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts
@@ -227,16 +227,6 @@
     });
   }
 
-  patchAlert(patch: Patch, onPatchError) {
-    let patchRequest = new PatchRequest();
-    patchRequest.guid = this.alertSource.guid;
-    patchRequest.index = this.alertIndex;
-    patchRequest.patch = [patch];
-    patchRequest.sensorType = this.alertSourceType;
-
-    this.updateService.patch(patchRequest).subscribe(() => {}, onPatchError);
-  }
-
   onDeleteComment(index: number) {
     let commentText =  'Do you wish to delete the comment ';
     if (this.alertCommentsWrapper[index].alertComment.comment.length > 25 ) {