]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
97080a62ae4848d3bb652976db7988d3347957b8
[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 { Observable, Subscriber, timer as observableTimer } from 'rxjs';
6
7 import { DirectivesModule } from '~/app/shared/directives/directives.module';
8 import { configureTestBed, modalServiceShow } from '~/testing/unit-test-helper';
9 import { AlertPanelComponent } from '../alert-panel/alert-panel.component';
10 import { LoadingPanelComponent } from '../loading-panel/loading-panel.component';
11 import { CriticalConfirmationModalComponent } from './critical-confirmation-modal.component';
12 import { ModalService, PlaceholderService } from 'carbon-components-angular';
13 import { ModalCdsService } from '../../services/modal-cds.service';
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: any;
44   modalRef: any;
45
46   // Normally private - public was needed for the tests
47   constructor(public modalService: ModalCdsService) {}
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],
101       providers: [
102         ModalService,
103         PlaceholderService,
104         { provide: 'itemNames', useValue: [] },
105         { provide: 'itemDescription', useValue: 'entry' },
106         { provide: 'actionDescription', useValue: 'delete' }
107       ]
108     },
109     [CriticalConfirmationModalComponent]
110   );
111
112   beforeEach(() => {
113     mockFixture = TestBed.createComponent(MockComponent);
114     mockComponent = mockFixture.componentInstance;
115     spyOn(mockComponent.modalService, 'show').and.callFake((_modalComp, config) => {
116       const data = modalServiceShow(CriticalConfirmationModalComponent, config);
117       component = data.componentInstance;
118       return data;
119     });
120     mockComponent.openCtrlDriven();
121     mockFixture.detectChanges();
122   });
123
124   it('should create', () => {
125     expect(component).toBeTruthy();
126   });
127
128   it('should throw an error if no action is defined', () => {
129     component = Object.assign(component, {
130       submitAction: null,
131       submitActionObservable: null
132     });
133     expect(() => component.ngOnInit()).toThrowError('No submit action defined');
134   });
135
136   it('should test if the ctrl driven mock is set correctly through mock component', () => {
137     expect(component.bodyTemplate).toBeTruthy();
138     expect(component.submitAction).toBeTruthy();
139     expect(component.submitActionObservable).not.toBeTruthy();
140   });
141
142   it('should test if the modal driven mock is set correctly through mock component', () => {
143     mockComponent.openModalDriven();
144     expect(component.bodyTemplate).toBeTruthy();
145     expect(component.submitActionObservable).toBeTruthy();
146     expect(component.submitAction).not.toBeTruthy();
147   });
148
149   describe('component functions', () => {
150     const changeValue = (value: boolean) => {
151       const ctrl = component.deletionForm.get('confirmation');
152       ctrl.setValue(value);
153       ctrl.markAsDirty();
154       ctrl.updateValueAndValidity();
155     };
156
157     it('should test hideModal', () => {
158       expect(component.hideModal).toBeTruthy();
159       spyOn(component, 'closeModal').and.callThrough();
160       expect(component.closeModal).not.toHaveBeenCalled();
161       component.hideModal();
162       expect(component.closeModal).toHaveBeenCalled();
163     });
164
165     describe('validate confirmation', () => {
166       const testValidation = (submitted: boolean, error: string, expected: boolean) => {
167         expect(
168           component.deletionForm.showError('confirmation', <NgForm>{ submitted: submitted }, error)
169         ).toBe(expected);
170       };
171
172       beforeEach(() => {
173         component.deletionForm.reset();
174       });
175
176       it('should test empty values', () => {
177         component.deletionForm.reset();
178         testValidation(true, 'required', true);
179         component.deletionForm.reset();
180         changeValue(true);
181         changeValue(false);
182         testValidation(true, 'required', true);
183       });
184     });
185
186     describe('deletion call', () => {
187       beforeEach(() => {
188         spyOn(component, 'stopLoadingSpinner').and.callThrough();
189         spyOn(component, 'hideModal').and.callThrough();
190       });
191
192       describe('Controller driven', () => {
193         beforeEach(() => {
194           spyOn(component, 'submitAction').and.callThrough();
195           spyOn(mockComponent.ctrlRef, 'close').and.callThrough();
196         });
197
198         it('should test fake deletion that closes modal', fakeAsync(() => {
199           // Before deletionCall
200           expect(component.submitAction).not.toHaveBeenCalled();
201           // During deletionCall
202           component.callSubmitAction();
203           expect(component.stopLoadingSpinner).not.toHaveBeenCalled();
204           expect(component.hideModal).not.toHaveBeenCalled();
205           expect(mockComponent.ctrlRef.close).not.toHaveBeenCalled();
206           expect(component.submitAction).toHaveBeenCalled();
207           expect(mockComponent.finished).toBe(undefined);
208           // After deletionCall
209           tick(2000);
210           expect(component.hideModal).not.toHaveBeenCalled();
211           expect(mockComponent.ctrlRef.close).toHaveBeenCalled();
212           expect(mockComponent.finished).toEqual([6, 7, 8, 9]);
213         }));
214       });
215
216       describe('Modal driven', () => {
217         beforeEach(() => {
218           mockComponent.openModalDriven();
219           spyOn(component, 'stopLoadingSpinner').and.callThrough();
220           spyOn(component, 'hideModal').and.callThrough();
221           spyOn(mockComponent, 'fakeDelete').and.callThrough();
222         });
223
224         it('should delete and close modal', fakeAsync(() => {
225           // During deletionCall
226           component.callSubmitAction();
227           expect(mockComponent.finished).toBe(undefined);
228           expect(component.hideModal).not.toHaveBeenCalled();
229           // After deletionCall
230           tick(2000);
231           expect(mockComponent.finished).toEqual([6, 7, 8, 9]);
232           expect(component.stopLoadingSpinner).not.toHaveBeenCalled();
233           expect(component.hideModal).toHaveBeenCalled();
234         }));
235       });
236     });
237   });
238 });