]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
e501d9f329ad61b61a0ff85050797772900c2b0f
[ceph.git] /
1 import { Component, NgModule, NO_ERRORS_SCHEMA, TemplateRef, ViewChild } from '@angular/core';
2 import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
3 import { NgForm, ReactiveFormsModule } from '@angular/forms';
4
5 import { NgbActiveModal, NgbModalModule, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
6 import { Observable, Subscriber, timer as observableTimer } from 'rxjs';
7
8 import { DirectivesModule } from '~/app/shared/directives/directives.module';
9 import { ModalService } from '~/app/shared/services/modal.service';
10 import { configureTestBed, modalServiceShow } from '~/testing/unit-test-helper';
11 import { AlertPanelComponent } from '../alert-panel/alert-panel.component';
12 import { LoadingPanelComponent } from '../loading-panel/loading-panel.component';
13 import { CriticalConfirmationModalComponent } from './critical-confirmation-modal.component';
14
15 @NgModule({})
16 export class MockModule {}
17
18 @Component({
19   template: `
20     <button type="button" class="btn btn-danger" (click)="openCtrlDriven()">
21       <i class="fa fa-times"></i>Deletion Ctrl-Test
22       <ng-template #ctrlDescription>
23         The spinner is handled by the controller if you have use the modal as ViewChild in order to
24         use it's functions to stop the spinner or close the dialog.
25       </ng-template>
26     </button>
27
28     <button type="button" class="btn btn-danger" (click)="openModalDriven()">
29       <i class="fa fa-times"></i>Deletion Modal-Test
30       <ng-template #modalDescription>
31         The spinner is handled by the modal if your given deletion function returns a Observable.
32       </ng-template>
33     </button>
34   `
35 })
36 class MockComponent {
37   @ViewChild('ctrlDescription', { static: true })
38   ctrlDescription: TemplateRef<any>;
39   @ViewChild('modalDescription', { static: true })
40   modalDescription: TemplateRef<any>;
41   someData = [1, 2, 3, 4, 5];
42   finished: number[];
43   ctrlRef: NgbModalRef;
44   modalRef: NgbModalRef;
45
46   // Normally private - public was needed for the tests
47   constructor(public modalService: ModalService) {}
48
49   openCtrlDriven() {
50     this.ctrlRef = this.modalService.show(CriticalConfirmationModalComponent, {
51       submitAction: this.fakeDeleteController.bind(this),
52       bodyTemplate: this.ctrlDescription
53     });
54   }
55
56   openModalDriven() {
57     this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
58       submitActionObservable: this.fakeDelete(),
59       bodyTemplate: this.modalDescription
60     });
61   }
62
63   finish() {
64     this.finished = [6, 7, 8, 9];
65   }
66
67   fakeDelete() {
68     return (): Observable<any> => {
69       return new Observable((observer: Subscriber<any>) => {
70         observableTimer(100).subscribe(() => {
71           observer.next(this.finish());
72           observer.complete();
73         });
74       });
75     };
76   }
77
78   fakeDeleteController() {
79     observableTimer(100).subscribe(() => {
80       this.finish();
81       this.ctrlRef.close();
82     });
83   }
84 }
85
86 describe('CriticalConfirmationModalComponent', () => {
87   let mockComponent: MockComponent;
88   let component: CriticalConfirmationModalComponent;
89   let mockFixture: ComponentFixture<MockComponent>;
90
91   configureTestBed(
92     {
93       declarations: [
94         MockComponent,
95         CriticalConfirmationModalComponent,
96         LoadingPanelComponent,
97         AlertPanelComponent
98       ],
99       schemas: [NO_ERRORS_SCHEMA],
100       imports: [ReactiveFormsModule, MockModule, DirectivesModule, NgbModalModule],
101       providers: [NgbActiveModal]
102     },
103     [CriticalConfirmationModalComponent]
104   );
105
106   beforeEach(() => {
107     mockFixture = TestBed.createComponent(MockComponent);
108     mockComponent = mockFixture.componentInstance;
109     spyOn(mockComponent.modalService, 'show').and.callFake((_modalComp, config) => {
110       const data = modalServiceShow(CriticalConfirmationModalComponent, config);
111       component = data.componentInstance;
112       return data;
113     });
114     mockComponent.openCtrlDriven();
115     mockFixture.detectChanges();
116   });
117
118   it('should create', () => {
119     expect(component).toBeTruthy();
120   });
121
122   it('should throw an error if no action is defined', () => {
123     component = Object.assign(component, {
124       submitAction: null,
125       submitActionObservable: null
126     });
127     expect(() => component.ngOnInit()).toThrowError('No submit action defined');
128   });
129
130   it('should test if the ctrl driven mock is set correctly through mock component', () => {
131     expect(component.bodyTemplate).toBeTruthy();
132     expect(component.submitAction).toBeTruthy();
133     expect(component.submitActionObservable).not.toBeTruthy();
134   });
135
136   it('should test if the modal driven mock is set correctly through mock component', () => {
137     mockComponent.openModalDriven();
138     expect(component.bodyTemplate).toBeTruthy();
139     expect(component.submitActionObservable).toBeTruthy();
140     expect(component.submitAction).not.toBeTruthy();
141   });
142
143   describe('component functions', () => {
144     const changeValue = (value: boolean) => {
145       const ctrl = component.deletionForm.get('confirmation');
146       ctrl.setValue(value);
147       ctrl.markAsDirty();
148       ctrl.updateValueAndValidity();
149       mockFixture.detectChanges();
150     };
151
152     it('should test hideModal', () => {
153       expect(component.activeModal).toBeTruthy();
154       expect(component.hideModal).toBeTruthy();
155       spyOn(component.activeModal, 'close').and.callThrough();
156       expect(component.activeModal.close).not.toHaveBeenCalled();
157       component.hideModal();
158       expect(component.activeModal.close).toHaveBeenCalled();
159     });
160
161     describe('validate confirmation', () => {
162       const testValidation = (submitted: boolean, error: string, expected: boolean) => {
163         expect(
164           component.deletionForm.showError('confirmation', <NgForm>{ submitted: submitted }, error)
165         ).toBe(expected);
166       };
167
168       beforeEach(() => {
169         component.deletionForm.reset();
170       });
171
172       it('should test empty values', () => {
173         component.deletionForm.reset();
174         testValidation(false, undefined, false);
175         testValidation(true, 'required', true);
176         component.deletionForm.reset();
177         changeValue(true);
178         changeValue(false);
179         testValidation(true, 'required', true);
180       });
181     });
182
183     describe('deletion call', () => {
184       beforeEach(() => {
185         spyOn(component, 'stopLoadingSpinner').and.callThrough();
186         spyOn(component, 'hideModal').and.callThrough();
187       });
188
189       describe('Controller driven', () => {
190         beforeEach(() => {
191           spyOn(component, 'submitAction').and.callThrough();
192           spyOn(mockComponent.ctrlRef, 'close').and.callThrough();
193         });
194
195         it('should test fake deletion that closes modal', fakeAsync(() => {
196           // Before deletionCall
197           expect(component.submitAction).not.toHaveBeenCalled();
198           // During deletionCall
199           component.callSubmitAction();
200           expect(component.stopLoadingSpinner).not.toHaveBeenCalled();
201           expect(component.hideModal).not.toHaveBeenCalled();
202           expect(mockComponent.ctrlRef.close).not.toHaveBeenCalled();
203           expect(component.submitAction).toHaveBeenCalled();
204           expect(mockComponent.finished).toBe(undefined);
205           // After deletionCall
206           tick(2000);
207           expect(component.hideModal).not.toHaveBeenCalled();
208           expect(mockComponent.ctrlRef.close).toHaveBeenCalled();
209           expect(mockComponent.finished).toEqual([6, 7, 8, 9]);
210         }));
211       });
212
213       describe('Modal driven', () => {
214         beforeEach(() => {
215           mockComponent.openModalDriven();
216           spyOn(component, 'stopLoadingSpinner').and.callThrough();
217           spyOn(component, 'hideModal').and.callThrough();
218           spyOn(mockComponent, 'fakeDelete').and.callThrough();
219         });
220
221         it('should delete and close modal', fakeAsync(() => {
222           // During deletionCall
223           component.callSubmitAction();
224           expect(mockComponent.finished).toBe(undefined);
225           expect(component.hideModal).not.toHaveBeenCalled();
226           // After deletionCall
227           tick(2000);
228           expect(mockComponent.finished).toEqual([6, 7, 8, 9]);
229           expect(component.stopLoadingSpinner).not.toHaveBeenCalled();
230           expect(component.hideModal).toHaveBeenCalled();
231         }));
232       });
233     });
234   });
235 });