| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * 'License'); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an 'AS IS' BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| import { AlertsListComponent } from './alerts-list.component'; |
| import { ComponentFixture, async, TestBed, fakeAsync, tick } from '@angular/core/testing'; |
| import { Component, Input, Directive } from '@angular/core'; |
| import { RouterTestingModule } from '@angular/router/testing'; |
| import { SearchService } from 'app/service/search.service'; |
| import { UpdateService } from 'app/service/update.service'; |
| import { ConfigureTableService } from 'app/service/configure-table.service'; |
| import { AlertsService } from 'app/service/alerts.service'; |
| import { ClusterMetaDataService } from 'app/service/cluster-metadata.service'; |
| import { SaveSearchService } from 'app/service/save-search.service'; |
| import { MetaAlertService } from 'app/service/meta-alert.service'; |
| import { GlobalConfigService } from 'app/service/global-config.service'; |
| import { DialogService } from 'app/service/dialog.service'; |
| import { TIMESTAMP_FIELD_NAME } from 'app/utils/constants'; |
| import { By } from '@angular/platform-browser'; |
| import { Observable, Subject, of, throwError } from 'rxjs'; |
| import { Filter } from 'app/model/filter'; |
| import { QueryBuilder, FilteringMode } from './query-builder'; |
| import { SearchResponse } from 'app/model/search-response'; |
| import { AutoPollingService } from './auto-polling/auto-polling.service'; |
| 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', |
| template: '<div></div>', |
| }) |
| class MockAutoPollingComponent {} |
| |
| @Component({ |
| selector: 'app-configure-rows', |
| template: '<div></div>', |
| }) |
| class MockConfigureRowsComponent { |
| @Input() refreshInterval = 0; |
| @Input() srcElement = {}; |
| @Input() pageSize = 0; |
| } |
| |
| @Component({ |
| selector: 'app-modal-loading-indicator', |
| template: '<div></div>', |
| }) |
| class MockModalLoadingIndicatorComponent { |
| @Input() show = false; |
| } |
| |
| @Component({ |
| selector: 'app-time-range', |
| template: '<div></div>', |
| }) |
| class MockTimeRangeComponent { |
| @Input() disabled = false; |
| @Input() selectedTimeRange = {}; |
| } |
| |
| @Directive({ |
| selector: '[appAceEditor]', |
| }) |
| class MockAceEditorDirective { |
| @Input() text = ''; |
| } |
| |
| @Component({ |
| selector: 'app-alert-filters', |
| template: '<div></div>', |
| }) |
| class MockAlertFilterComponent { |
| @Input() facets = []; |
| } |
| |
| @Component({ |
| selector: 'app-group-by', |
| template: '<div></div>', |
| }) |
| class MockGroupByComponent { |
| @Input() facets = []; |
| } |
| |
| @Component({ |
| selector: 'app-table-view', |
| template: '<div></div>', |
| }) |
| class MockTableViewComponent { |
| @Input() alerts = []; |
| @Input() pagination = {}; |
| @Input() alertsColumnsToDisplay = []; |
| @Input() selectedAlerts = []; |
| } |
| |
| @Component({ |
| selector: 'app-tree-view', |
| template: '<div></div>', |
| }) |
| class MockTreeViewComponent { |
| @Input() alerts = []; |
| @Input() pagination = {}; |
| @Input() alertsColumnsToDisplay = []; |
| @Input() selectedAlerts = []; |
| @Input() globalConfig = {}; |
| @Input() query = ''; |
| @Input() groups = []; |
| } |
| |
| |
| describe('AlertsListComponent', () => { |
| |
| let component: AlertsListComponent; |
| let fixture: ComponentFixture<AlertsListComponent>; |
| |
| let queryBuilder: QueryBuilder; |
| let searchService: SearchService; |
| |
| beforeEach(async(() => { |
| |
| const searchResponseFake = new SearchResponse(); |
| searchResponseFake.facetCounts = {}; |
| |
| TestBed.configureTestingModule({ |
| imports: [ |
| RouterTestingModule.withRoutes([{path: 'alerts-list', component: AlertsListComponent}]), |
| ], |
| declarations: [ |
| AlertsListComponent, |
| MockAutoPollingComponent, |
| MockModalLoadingIndicatorComponent, |
| MockTimeRangeComponent, |
| MockAceEditorDirective, |
| MockConfigureRowsComponent, |
| MockAlertFilterComponent, |
| MockGroupByComponent, |
| MockTableViewComponent, |
| MockTreeViewComponent, |
| ], |
| providers: [ |
| { provide: SearchService, useClass: () => { return { |
| search: () => of(searchResponseFake), |
| } } }, |
| { 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 { |
| getDefaultColumns: () => new Observable(), |
| } } }, |
| { 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(), |
| } } }, |
| { provide: DialogService, useClass: () => { return {} } }, |
| { provide: QueryBuilder, useClass: () => { return { |
| filters: [], |
| query: '*', |
| searchRequest: () => { |
| return new SearchResponse(); |
| }, |
| addOrUpdateFilter: () => {}, |
| clearSearch: () => {}, |
| isTimeStampFieldPresent: () => {}, |
| getManualQuery: () => {}, |
| setManualQuery: () => {}, |
| getFilteringMode: () => {}, |
| setFilteringMode: () => {}, |
| setSearch: () => {}, |
| } } }, |
| { provide: AutoPollingService, useClass: () => { return { |
| data: new Subject<SearchResponse>(), |
| getIsCongestion: () => {}, |
| getInterval: () => {}, |
| getIsPollingActive: () => {}, |
| dropNextAndContinue: () => {}, |
| onDestroy: () => {}, |
| setSuppression: () => {}, |
| setInterval: () => {}, |
| } } }, |
| ] |
| }) |
| .compileComponents(); |
| |
| queryBuilder = TestBed.get(QueryBuilder); |
| searchService = TestBed.get(SearchService); |
| })); |
| |
| beforeEach(() => { |
| fixture = TestBed.createComponent(AlertsListComponent); |
| component = fixture.componentInstance; |
| fixture.detectChanges(); |
| }); |
| |
| it('should exist', () => { |
| 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'); |
| }); |
| |
| it('default query time range from date should be set', () => { |
| expect(component.selectedTimeRange.dateFilterValue.fromDate).toBeTruthy(); |
| }); |
| |
| it('default query time range to date should be set', () => { |
| expect(component.selectedTimeRange.dateFilterValue.toDate).toBeTruthy(); |
| }); |
| |
| it('shows subtotals in view when onTreeViewChange is truthy', () => { |
| component.onTreeViewChange(4); |
| fixture.detectChanges(); |
| let subtotal = fixture.nativeElement.querySelector('[data-qe-id="alert-subgroup-total"]'); |
| expect(subtotal.textContent).toEqual('Alerts in Groups (4)'); |
| |
| component.onTreeViewChange(0); |
| fixture.detectChanges(); |
| expect(fixture.nativeElement.querySelector('[data-qe-id="alert-subgroup-total"]')).toBeNull(); |
| }); |
| |
| describe('filtering by query builder or manual query', () => { |
| it('should be able to toggle the query builder mode', () => { |
| spyOn(component, 'setSearchRequestSize'); |
| spyOn(queryBuilder, 'setFilteringMode'); |
| |
| queryBuilder.getFilteringMode = () => FilteringMode.BUILDER; |
| |
| component.toggleQueryBuilderMode(); |
| expect(queryBuilder.setFilteringMode).toHaveBeenCalledWith(FilteringMode.MANUAL); |
| |
| queryBuilder.getFilteringMode = () => FilteringMode.MANUAL; |
| |
| component.toggleQueryBuilderMode(); |
| expect(queryBuilder.setFilteringMode).toHaveBeenCalledWith(FilteringMode.BUILDER); |
| }); |
| |
| it('isQueryBuilderModeManual should return true if queryBuilder is in manual mode', () => { |
| queryBuilder.getFilteringMode = () => FilteringMode.MANUAL; |
| expect(component.isQueryBuilderModeManual()).toBe(true); |
| |
| queryBuilder.getFilteringMode = () => FilteringMode.BUILDER; |
| expect(component.isQueryBuilderModeManual()).toBe(false); |
| }); |
| |
| it('should show manual input dom element depending on mode', () => { |
| let input = fixture.debugElement.query(By.css('[data-qe-id="manual-query-input"]')); |
| |
| expect(input).toBeFalsy(); |
| |
| queryBuilder.getFilteringMode = () => FilteringMode.MANUAL; |
| fixture.detectChanges(); |
| input = fixture.debugElement.query(By.css('[data-qe-id="manual-query-input"]')); |
| |
| expect(input).toBeTruthy(); |
| |
| queryBuilder.getFilteringMode = () => FilteringMode.BUILDER; |
| fixture.detectChanges(); |
| input = fixture.debugElement.query(By.css('[data-qe-id="manual-query-input"]')); |
| |
| expect(input).toBeFalsy(); |
| }); |
| |
| it('should bind default manual query from query builder', () => { |
| spyOn(queryBuilder, 'getManualQuery').and.returnValue('test manual query string') |
| |
| queryBuilder.getFilteringMode = () => FilteringMode.MANUAL; |
| fixture.detectChanges(); |
| let input: HTMLInputElement = fixture.debugElement.query(By.css('[data-qe-id="manual-query-input"]')).nativeElement; |
| |
| expect(input.value).toBe('test manual query string'); |
| }); |
| |
| it('should pass the manual query value to the query builder when editing mode is manual', fakeAsync(() => { |
| spyOn(queryBuilder, 'setManualQuery'); |
| |
| queryBuilder.getFilteringMode = () => FilteringMode.MANUAL; |
| fixture.detectChanges(); |
| |
| const input = fixture.debugElement.query(By.css('[data-qe-id="manual-query-input"]')); |
| const el = input.nativeElement; |
| |
| el.value = 'test'; |
| (el as HTMLElement).dispatchEvent(new Event('keyup')); |
| fixture.detectChanges(); |
| tick(300); |
| |
| expect(queryBuilder.setManualQuery).toHaveBeenCalledWith('test'); |
| })); |
| }); |
| |
| describe('handling pending search requests', () => { |
| it('should set pendingSearch on search', () => { |
| spyOn(searchService, 'search').and.returnValue(of(new SearchResponse())); |
| spyOn(component, 'saveCurrentSearch'); |
| spyOn(component, 'setSearchRequestSize'); |
| spyOn(component, 'setSelectedTimeRange'); |
| spyOn(component, 'createGroupFacets'); |
| |
| component.search(); |
| expect(component.pendingSearch).toBeTruthy(); |
| }); |
| |
| it('should clear pendingSearch on search success', (done) => { |
| const fakeObservable = new Subject(); |
| spyOn(searchService, 'search').and.returnValue(fakeObservable); |
| spyOn(component, 'saveCurrentSearch'); |
| spyOn(component, 'setSearchRequestSize'); |
| spyOn(component, 'setSelectedTimeRange'); |
| spyOn(component, 'createGroupFacets'); |
| |
| component.search(); |
| |
| setTimeout(() => { |
| fakeObservable.next(new SearchResponse()); |
| }, 0); |
| |
| fakeObservable.subscribe(() => { |
| expect(component.pendingSearch).toBe(null); |
| done(); |
| }) |
| }); |
| }); |
| |
| describe('stale data state', () => { |
| it('should set staleDataState flag to true on filter change', () => { |
| expect(component.staleDataState).toBe(false); |
| component.onAddFilter(new Filter('ip_src_addr', '0.0.0.0')); |
| expect(component.staleDataState).toBe(true); |
| }); |
| |
| it('should set staleDataState flag to true on filter clearing', () => { |
| spyOn(component, 'setSearchRequestSize'); |
| |
| expect(component.staleDataState).toBe(false); |
| component.onClear(); |
| expect(component.staleDataState).toBe(true); |
| }); |
| |
| it('should set staleDataState flag to true on timerange change', () => { |
| expect(component.staleDataState).toBe(false); |
| component.onTimeRangeChange(new Filter(TIMESTAMP_FIELD_NAME, 'this-year')); |
| expect(component.staleDataState).toBe(true); |
| }); |
| |
| it('should set staleDataState flag to false when the query resolves', () => { |
| spyOn(searchService, 'search').and.returnValue(of(new SearchResponse())); |
| spyOn(component, 'saveCurrentSearch'); |
| spyOn(component, 'setSearchRequestSize'); |
| spyOn(component, 'setSelectedTimeRange'); |
| spyOn(component, 'createGroupFacets'); |
| |
| component.staleDataState = true; |
| component.search(); |
| expect(component.staleDataState).toBe(false); |
| }); |
| |
| it('should set stale date true when query changes in manual mode', fakeAsync(() => { |
| queryBuilder.getFilteringMode = () => FilteringMode.MANUAL; |
| |
| fixture.detectChanges(); |
| const input = fixture.debugElement.query(By.css('[data-qe-id="manual-query-input"]')); |
| const el = input.nativeElement; |
| |
| el.value = 'test'; |
| (el as HTMLElement).dispatchEvent(new Event('keyup')); |
| fixture.detectChanges(); |
| tick(300); |
| |
| expect(component.staleDataState).toBe(true); |
| })); |
| |
| it('should show warning if data is in a stale state', () => { |
| expect(fixture.debugElement.query(By.css('[data-qe-id="staleDataWarning"]'))).toBe(null); |
| |
| component.staleDataState = true; |
| fixture.detectChanges(); |
| |
| expect(fixture.debugElement.query(By.css('[data-qe-id="staleDataWarning"]'))).toBeTruthy(); |
| }); |
| |
| }); |
| |
| describe('auto polling', () => { |
| it('should refresh view on data emit', () => { |
| const fakeResponse = new SearchResponse(); |
| spyOn(component, 'setData'); |
| |
| TestBed.get(AutoPollingService).data.next(fakeResponse); |
| |
| expect(component.setData).toHaveBeenCalledWith(fakeResponse); |
| }); |
| |
| it('should set staleDataState false on auto polling refresh', () => { |
| spyOn(component, 'setData'); |
| component.staleDataState = true; |
| |
| TestBed.get(AutoPollingService).data.next(new SearchResponse()); |
| |
| expect(component.staleDataState).toBe(false); |
| }); |
| |
| it('should show warning on auto polling congestion', () => { |
| expect(fixture.debugElement.query(By.css('[data-qe-id="pollingCongestionWarning"]'))).toBeFalsy(); |
| |
| TestBed.get(AutoPollingService).getIsCongestion = () => true; |
| fixture.detectChanges(); |
| |
| expect(fixture.debugElement.query(By.css('[data-qe-id="pollingCongestionWarning"]'))).toBeTruthy(); |
| |
| TestBed.get(AutoPollingService).getIsCongestion = () => false; |
| fixture.detectChanges(); |
| |
| expect(fixture.debugElement.query(By.css('[data-qe-id="pollingCongestionWarning"]'))).toBeFalsy(); |
| }); |
| |
| it('should pass refresh interval to row config component', () => { |
| TestBed.get(AutoPollingService).getInterval = () => 44; |
| fixture.detectChanges(); |
| |
| expect(fixture.debugElement.query(By.directive(MockConfigureRowsComponent)).componentInstance.refreshInterval).toBe(44); |
| }); |
| |
| it('should drop pending auto polling result if user trigger search request manually', () => { |
| const autoPollingSvc = TestBed.get(AutoPollingService); |
| spyOn(autoPollingSvc, 'dropNextAndContinue'); |
| spyOn(component, 'setSearchRequestSize'); |
| |
| autoPollingSvc.getIsPollingActive = () => false; |
| component.search() |
| |
| expect(autoPollingSvc.dropNextAndContinue).not.toHaveBeenCalled(); |
| |
| autoPollingSvc.getIsPollingActive = () => true; |
| component.search() |
| |
| expect(autoPollingSvc.dropNextAndContinue).toHaveBeenCalled(); |
| }); |
| |
| it('should show different stale data warning when polling is active', () => { |
| const autoPollingSvc = TestBed.get(AutoPollingService); |
| |
| autoPollingSvc.getIsPollingActive = () => false; |
| const warning = component.getStaleDataWarning(); |
| |
| autoPollingSvc.getIsPollingActive = () => true; |
| const warningWhenPolling = component.getStaleDataWarning(); |
| |
| expect(warning).not.toEqual(warningWhenPolling); |
| }); |
| |
| it('should show getIsCongestion scennarios', () => { |
| const autoPollingSvc = TestBed.get(AutoPollingService); |
| |
| autoPollingSvc.getIsCongestion = () => false; |
| fixture.detectChanges(); |
| expect(fixture.debugElement.query(By.css('[data-qe-id="pollingCongestionWarning"]'))).toBeFalsy(); |
| |
| autoPollingSvc.getIsCongestion = () => true; |
| fixture.detectChanges(); |
| expect(fixture.debugElement.query(By.css('[data-qe-id="pollingCongestionWarning"]'))).toBeTruthy(); |
| |
| }); |
| |
| it('should suppress polling when user select alerts', () => { |
| const autoPollingSvc = TestBed.get(AutoPollingService); |
| spyOn(autoPollingSvc, 'setSuppression'); |
| |
| component.onSelectedAlertsChange([{ source: { metron_alert: [] } }]); |
| |
| expect(autoPollingSvc.setSuppression).toHaveBeenCalledWith(true); |
| }); |
| |
| it('should restore polling from suppression when user deselect alerts', () => { |
| const autoPollingSvc = TestBed.get(AutoPollingService); |
| spyOn(autoPollingSvc, 'setSuppression'); |
| |
| component.onSelectedAlertsChange([]); |
| |
| expect(autoPollingSvc.setSuppression).toHaveBeenCalledWith(false); |
| }); |
| |
| it('should suppress polling when open details pane', () => { |
| const autoPollingSvc = TestBed.get(AutoPollingService); |
| const router = TestBed.get(Router); |
| spyOn(router, 'navigate').and.returnValue(true); |
| spyOn(router, 'navigateByUrl').and.returnValue(true); |
| spyOn(autoPollingSvc, 'setSuppression'); |
| |
| component.showConfigureTable(); |
| |
| expect(autoPollingSvc.setSuppression).toHaveBeenCalledWith(true); |
| }); |
| |
| it('should suppress polling when open column config pane', () => { |
| const router = TestBed.get(Router); |
| const autoPollingSvc = TestBed.get(AutoPollingService); |
| spyOn(router, 'navigate'); |
| spyOn(router, 'navigateByUrl'); |
| spyOn(autoPollingSvc, 'setSuppression'); |
| |
| const fakeAlert = new Alert(); |
| fakeAlert.source = new AlertSource(); |
| |
| component.showDetails(fakeAlert); |
| |
| expect(autoPollingSvc.setSuppression).toHaveBeenCalledWith(true); |
| }); |
| |
| it('should suppress polling when open Saved Searches pane', () => { |
| const router = TestBed.get(Router); |
| const autoPollingSvc = TestBed.get(AutoPollingService); |
| spyOn(router, 'navigate'); |
| spyOn(router, 'navigateByUrl'); |
| spyOn(autoPollingSvc, 'setSuppression'); |
| |
| component.showSavedSearches(); |
| |
| expect(autoPollingSvc.setSuppression).toHaveBeenCalledWith(true); |
| }); |
| |
| it('should suppress polling when open Save Search dialogue pane', () => { |
| const router = TestBed.get(Router); |
| const autoPollingSvc = TestBed.get(AutoPollingService); |
| const saveSearchSvc = TestBed.get(SaveSearchService); |
| spyOn(router, 'navigate'); |
| spyOn(router, 'navigateByUrl'); |
| spyOn(autoPollingSvc, 'setSuppression'); |
| spyOn(saveSearchSvc, 'setCurrentQueryBuilderAndTableColumns'); |
| |
| component.showSaveSearch(); |
| |
| expect(autoPollingSvc.setSuppression).toHaveBeenCalledWith(true); |
| }); |
| |
| it('should restore the polling supression on bulk status update (other scenario of deselecting alerts)', () => { |
| const autoPollingSvc = TestBed.get(AutoPollingService); |
| spyOn(autoPollingSvc, 'setSuppression'); |
| |
| component.updateSelectedAlertStatus('fakeState'); |
| |
| expect(autoPollingSvc.setSuppression).toHaveBeenCalledWith(false); |
| }); |
| |
| it('should restore the polling supression when returning from a subroute', fakeAsync(() => { |
| const autoPollingSvc = TestBed.get(AutoPollingService); |
| spyOn(autoPollingSvc, 'setSuppression'); |
| |
| autoPollingSvc.getIsPollingActive = () => false; |
| fixture.ngZone.run(() => { |
| TestBed.get(Router).navigate(['/alerts-list']); |
| }); |
| |
| expect(autoPollingSvc.setSuppression).not.toHaveBeenCalled(); |
| |
| autoPollingSvc.getIsPollingActive = () => true; |
| fixture.ngZone.run(() => { |
| TestBed.get(Router).navigate(['/alerts-list']); |
| }); |
| |
| expect(autoPollingSvc.setSuppression).toHaveBeenCalledWith(false); |
| })); |
| }); |
| |
| 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); |
| |
| spyOn(searchService, 'search').and.returnValue(throwError(new RestError())); |
| fakeDialogService.launchDialog = () => {}; |
| spyOn(fakeDialogService, 'launchDialog'); |
| |
| component.search(); |
| |
| 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(); |
| }); |
| }); |
| }); |