METRON-2323 Increase unit test coverage for Alerts List (sardell) closes apache/metron#1567
diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html
index ea09288..a078e8f 100755
--- a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html
+++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html
@@ -76,13 +76,13 @@
                 <app-auto-polling #autoPolling></app-auto-polling>
 
                 <div id="table-actions" class="dropdown d-inline-block">
-                    <button class="btn btn-primary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">ACTIONS</button>
+                    <button class="btn btn-primary dropdown-toggle" type="button" id="dropdownMenuButton" data-qe-id="dropdown-menu-button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">ACTIONS</button>
                     <div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuButton">
-                        <span class="dropdown-item" [class.disabled]="selectedAlerts.length == 0" (click)="processOpen($event)">Open</span>
-                        <span class="dropdown-item" [class.disabled]="selectedAlerts.length == 0" (click)="processDismiss($event)">Dismiss</span>
-                        <span class="dropdown-item" [class.disabled]="selectedAlerts.length == 0" (click)="processEscalate($event)">Escalate</span>
-                        <span class="dropdown-item" [class.disabled]="selectedAlerts.length == 0" (click)="processResolve($event)">Resolve</span>
-                        <span class="dropdown-item" [class.disabled]="selectedAlerts.length == 0 || isMetaAlertPresentInSelectedAlerts" (click)="processAddToAlert($event)">Add to Alert</span>
+                        <span class="dropdown-item" data-qe-id="action-open-button" [class.disabled]="selectedAlerts.length == 0" (click)="processOpen($event)">Open</span>
+                        <span class="dropdown-item" data-qe-id="action-dismiss-button" [class.disabled]="selectedAlerts.length == 0" (click)="processDismiss($event)">Dismiss</span>
+                        <span class="dropdown-item" data-qe-id="action-escalate-button" [class.disabled]="selectedAlerts.length == 0" (click)="processEscalate($event)">Escalate</span>
+                        <span class="dropdown-item" data-qe-id="action-resolve-button" [class.disabled]="selectedAlerts.length == 0" (click)="processResolve($event)">Resolve</span>
+                        <span class="dropdown-item" data-qe-id="action-add-to-alert-button" [class.disabled]="selectedAlerts.length == 0 || isMetaAlertPresentInSelectedAlerts" (click)="processAddToAlert($event)">Add to Alert</span>
                     </div>
                 </div>
             </div>
diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.spec.ts b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.spec.ts
index 74d0f8c..7238555 100644
--- a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.spec.ts
+++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.spec.ts
@@ -35,13 +35,15 @@
 import { QueryBuilder, FilteringMode } from './query-builder';
 import { SearchResponse } from 'app/model/search-response';
 import { AutoPollingService } from './auto-polling/auto-polling.service';
-import { Router } from '@angular/router';
+import { Router, NavigationStart } from '@angular/router';
 import { Alert } from 'app/model/alert';
 import { AlertSource } from 'app/model/alert-source';
 import { SearchRequest } from 'app/model/search-request';
 import { query } from '@angular/core/src/render3';
 import { RestError } from 'app/model/rest-error';
 import { DialogType } from 'app/shared/metron-dialog/metron-dialog.component';
+import { DateFilterValue } from 'app/model/date-filter-value';
+import { SaveSearch } from 'app/model/save-search';
 
 @Component({
   selector: 'app-auto-polling',
@@ -160,10 +162,12 @@
         } } },
         { provide: UpdateService, useClass: () => { return {
           alertChanged$: new Observable(),
+          updateAlertState: () => of(),
         } } },
         { provide: ConfigureTableService, useClass: () => { return {
           getTableMetadata: () => new Observable(),
           tableChanged$: new Observable(),
+          saveTableMetaData: () => of(),
         } } },
         { provide: AlertsService, useClass: () => { return {} } },
         { provide: ClusterMetaDataService, useClass: () => { return {
@@ -172,9 +176,14 @@
         { provide: SaveSearchService, useClass: () => { return {
           loadSavedSearch$: new Observable(),
           setCurrentQueryBuilderAndTableColumns: () => {},
+          fireLoadSavedSearch: (savedSearch: any) => {
+            this.loadSavedSearch$.next(savedSearch);
+          },
+          saveAsRecentSearches: (savedSearch: any) => of(),
         } } },
         { provide: MetaAlertService, useClass: () => { return {
           alertChanged$: new Observable(),
+          selectedAlerts: []
         } } },
         { provide: GlobalConfigService, useClass: () => { return {
           get: () => new Observable(),
@@ -183,7 +192,7 @@
         { provide: QueryBuilder, useClass: () => { return {
           filters: [],
           query: '*',
-          get searchRequest() {
+          searchRequest: () => {
             return new SearchResponse();
           },
           addOrUpdateFilter: () => {},
@@ -193,6 +202,7 @@
           setManualQuery: () => {},
           getFilteringMode: () => {},
           setFilteringMode: () => {},
+          setSearch: () => {},
         } } },
         { provide: AutoPollingService, useClass: () => { return {
           data: new Subject<SearchResponse>(),
@@ -202,6 +212,7 @@
           dropNextAndContinue: () => {},
           onDestroy: () => {},
           setSuppression: () => {},
+          setInterval: () => {},
         } } },
       ]
     })
@@ -221,6 +232,28 @@
     expect(component).toBeTruthy();
   });
 
+  it('should get global config on init', () => {
+    const globalConfig = { 'source.type.field': 'test'}
+    const globalConfigService = TestBed.get(GlobalConfigService);
+    spyOn(globalConfigService, 'get').and.returnValue(of(globalConfig));
+    component.ngOnInit();
+    component.alertsColumns = [
+      { name: 'ip:source', type: 'testType' },
+      { name: 'source:type', type: 'testType' }
+    ];
+    fixture.detectChanges();
+    expect(component.globalConfig).toEqual(globalConfig);
+    expect(component.alertsColumns.length).toEqual(2);
+  });
+
+  it('should clear selected alerts if NavigationStart', () => {
+    const router = TestBed.get(Router);
+    spyOn(router, 'events').and.returnValue({url: '/alerts-list'} instanceof NavigationStart);
+    component.ngOnInit();
+    fixture.detectChanges();
+    expect(component.selectedAlerts).toEqual([]);
+  });
+
   it('should set default query time range', () => {
     expect(component.selectedTimeRange instanceof Filter).toBeTruthy();
     expect(component.selectedTimeRange.value).toBe('last-15-minutes');
@@ -589,6 +622,17 @@
   });
 
   describe('search', () => {
+    it('should fire onSearch if in manual search mode', () => {
+      const testQuery = 'test';
+      spyOn(queryBuilder, 'setFilteringMode').and.returnValue(FilteringMode.BUILDER);
+      spyOn(queryBuilder, 'setSearch');
+      spyOn(component, 'search');
+      component.toggleQueryBuilderMode();
+      fixture.detectChanges();
+      component.onSearch(testQuery);
+      expect(queryBuilder.setSearch).toHaveBeenCalledWith(testQuery);
+    });
+
     it('should show notification on http error', fakeAsync(() => {
       const fakeDialogService = TestBed.get(DialogService);
 
@@ -600,5 +644,141 @@
 
       expect(fakeDialogService.launchDialog).toHaveBeenCalledWith('Server were unable to apply query string.', DialogType.Error);
     }));
+
+    it('should save current search', () => {
+      const saveSearchService = TestBed.get(SaveSearchService);
+      const search = new SaveSearch();
+
+      spyOn(saveSearchService, 'saveAsRecentSearches').and.callThrough();
+      spyOn(queryBuilder, 'query').and.returnValue('test');
+      component.saveCurrentSearch(search);
+      expect(saveSearchService.saveAsRecentSearches).toHaveBeenCalledWith(search);
+    });
+  });
+
+ describe('actions', () => {
+    const testAlert: Alert = {
+      id: '123',
+      score: 123,
+      source: new AlertSource(),
+      status: 'TEST',
+      index: 'test'
+    }
+
+    it('should prevent a user from selecting a new alert state if disabled', () => {
+      const updateService = TestBed.get(UpdateService);
+      spyOn(updateService, 'updateAlertState')
+      spyOn(component, 'preventDropdownOptionIfDisabled');
+      const actionsButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="dropdown-menu-button"');
+      actionsButton.click();
+      const openButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="action-open-button"');
+      expect(openButton.classList).toContain('disabled');
+      openButton.dispatchEvent(new Event('click'));
+      expect(component.preventDropdownOptionIfDisabled).toHaveBeenCalled();
+      expect(updateService.updateAlertState).not.toHaveBeenCalled();
+    });
+
+
+    it('should update the alert state to open when selected', () => {
+      component.selectedAlerts.push(testAlert);
+      fixture.detectChanges();
+      const updateService = TestBed.get(UpdateService);
+      spyOn(updateService, 'updateAlertState').and.returnValue(of({}));
+      spyOn(component, 'processOpen').and.callThrough();
+      spyOn(component, 'updateSelectedAlertStatus');
+      const actionsButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="dropdown-menu-button"');
+      actionsButton.click();
+      const openButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="action-open-button"');
+      openButton.dispatchEvent(new Event('click'));
+      fixture.detectChanges();
+      expect(component.processOpen).toHaveBeenCalled();
+      expect(updateService.updateAlertState).toHaveBeenCalledWith(component.selectedAlerts, 'OPEN', false);
+    });
+
+    it('should update the alert state to dismiss when selected', () => {
+      component.selectedAlerts.push(testAlert);
+      fixture.detectChanges();
+      const updateService = TestBed.get(UpdateService);
+      spyOn(updateService, 'updateAlertState').and.returnValue(of());
+      spyOn(component, 'processDismiss').and.callThrough();
+      spyOn(component, 'updateSelectedAlertStatus');
+      const actionsButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="dropdown-menu-button"');
+      actionsButton.click();
+      const dismissButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="action-dismiss-button"');
+      dismissButton.dispatchEvent(new Event('click'));
+      fixture.detectChanges();
+      expect(component.processDismiss).toHaveBeenCalled();
+      expect(updateService.updateAlertState).toHaveBeenCalledWith(component.selectedAlerts, 'DISMISS', false);
+    });
+
+    it('should update the alert state to escalate when selected', () => {
+      component.selectedAlerts.push(testAlert);
+      fixture.detectChanges();
+      const updateService = TestBed.get(UpdateService);
+      spyOn(updateService, 'updateAlertState').and.returnValue(of());
+      spyOn(component, 'processEscalate').and.callThrough();
+      spyOn(component, 'updateSelectedAlertStatus');
+      const actionsButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="dropdown-menu-button"');
+      actionsButton.click();
+      const escalateButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="action-escalate-button"');
+      escalateButton.dispatchEvent(new Event('click'));
+      fixture.detectChanges();
+      expect(component.processEscalate).toHaveBeenCalled();
+      expect(updateService.updateAlertState).toHaveBeenCalledWith(component.selectedAlerts, 'ESCALATE', false);
+    });
+
+    it('should update the alert state to resolve when selected', () => {
+      component.selectedAlerts.push(testAlert);
+      fixture.detectChanges();
+      const updateService = TestBed.get(UpdateService);
+      spyOn(updateService, 'updateAlertState').and.returnValue(of());
+      spyOn(component, 'processResolve').and.callThrough();
+      spyOn(component, 'updateSelectedAlertStatus');
+      const actionsButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="dropdown-menu-button"');
+      actionsButton.click();
+      const resolveButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="action-resolve-button"');
+      resolveButton.dispatchEvent(new Event('click'));
+      fixture.detectChanges();
+      expect(component.processResolve).toHaveBeenCalled();
+      expect(updateService.updateAlertState).toHaveBeenCalledWith(component.selectedAlerts, 'RESOLVE', false);
+    });
+
+    it('should add to alert when selected', () => {
+      component.selectedAlerts.push(testAlert);
+      fixture.detectChanges();
+      const metaAlertService = TestBed.get(MetaAlertService);
+      const router = TestBed.get(Router);
+      spyOn(component, 'processAddToAlert').and.callThrough();
+      spyOn(component, 'updateSelectedAlertStatus');
+      spyOn(router, 'navigateByUrl');
+      const actionsButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="dropdown-menu-button"');
+      actionsButton.click();
+      const processAddToAlertButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="action-add-to-alert-button"');
+      processAddToAlertButton.dispatchEvent(new Event('click'));
+      fixture.detectChanges();
+      expect(component.processAddToAlert).toHaveBeenCalled();
+      expect(metaAlertService.selectedAlerts).toEqual(component.selectedAlerts);
+      expect(router.navigateByUrl).toHaveBeenCalledWith('/alerts-list(dialog:add-to-meta-alert)');
+    });
+  });
+
+  describe('table configuration', () => {
+    it('should reconfigure rows when value is emitted to configRowsChange', () => {
+      const configureTableService = TestBed.get(ConfigureTableService);
+      spyOn(component, 'updatePollingInterval');
+      spyOn(component, 'search');
+      spyOn(configureTableService, 'saveTableMetaData').and.callThrough();
+      component.onConfigRowsChange({
+        values: {
+          pageSize: 10,
+          refreshInterval: 1000
+        },
+        triggerQuery: true
+      });
+
+      expect(component.tableMetaData.size).toEqual(10);
+      expect(configureTableService.saveTableMetaData).toHaveBeenCalledWith(component.tableMetaData);
+      expect(component.search).toHaveBeenCalled();
+    });
   });
 });
diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts
index 1bb7a04..9e7f0b8 100755
--- a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts
+++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts
@@ -201,13 +201,6 @@
     }
   }
 
-  getColumnNamesForQuery() {
-    let fieldNames = this.alertsColumns.map(columnMetadata => columnMetadata.name);
-    fieldNames = fieldNames.filter(name => !(name === 'id' || name === 'alert_status'));
-    fieldNames.push(this.globalConfig['threat.score.field.name']);
-    return fieldNames;
-  }
-
   ngOnDestroy() {
     this.autoPollingSvc.onDestroy();
     this.removeAlertChangedListner();
@@ -442,15 +435,6 @@
 
   saveCurrentSearch(savedSearch: SaveSearch) {
     if (this.queryBuilder.query !== '*') {
-      if (!savedSearch) {
-        savedSearch = new SaveSearch();
-        savedSearch.searchRequest = this.queryBuilder.searchRequest;
-        savedSearch.tableColumns = this.alertsColumns;
-        savedSearch.filters = this.queryBuilder.filters;
-        savedSearch.searchRequest.query = '';
-        savedSearch.name = this.queryBuilder.generateNameForSearchRequest();
-      }
-
       this.saveSearchService.saveAsRecentSearches(savedSearch).subscribe(() => {
       });
     }