]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/blob
2e0706786e38f446c7ce377c80401155ac933f32
[ceph-ci.git] /
1 import { Component, NgModule, 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 { CheckboxModule, 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     declarations: [
93       MockComponent,
94       CriticalConfirmationModalComponent,
95       LoadingPanelComponent,
96       AlertPanelComponent
97     ],
98     imports: [ReactiveFormsModule, MockModule, DirectivesModule, CheckboxModule],
99     providers: [
100       ModalService,
101       PlaceholderService,
102       { provide: 'itemNames', useValue: [] },
103       { provide: 'itemDescription', useValue: 'entry' },
104       { provide: 'actionDescription', useValue: 'delete' }
105     ]
106   });
107
108   beforeEach(() => {
109     mockFixture = TestBed.createComponent(MockComponent);
110     mockComponent = mockFixture.componentInstance;
111     spyOn(mockComponent.modalService, 'show').and.callFake((_modalComp, config) => {
112       const data = modalServiceShow(CriticalConfirmationModalComponent, config);
113       component = data.componentInstance;
114       return data;
115     });
116     mockComponent.openCtrlDriven();
117     mockFixture.detectChanges();
118   });
119
120   it('should create', () => {
121     expect(component).toBeTruthy();
122   });
123
124   it('should throw an error if no action is defined', () => {
125     component = Object.assign(component, {
126       submitAction: null,
127       submitActionObservable: null
128     });
129     expect(() => component.ngOnInit()).toThrowError('No submit action defined');
130   });
131
132   it('should test if the ctrl driven mock is set correctly through mock component', () => {
133     expect(component.bodyTemplate).toBeTruthy();
134     expect(component.submitAction).toBeTruthy();
135     expect(component.submitActionObservable).not.toBeTruthy();
136   });
137
138   it('should test if the modal driven mock is set correctly through mock component', () => {
139     mockComponent.openModalDriven();
140     expect(component.bodyTemplate).toBeTruthy();
141     expect(component.submitActionObservable).toBeTruthy();
142     expect(component.submitAction).not.toBeTruthy();
143   });
144
145   describe('component functions', () => {
146     const changeValue = (value: boolean) => {
147       const ctrl = component.deletionForm.get('confirmation');
148       ctrl.setValue(value);
149       ctrl.markAsDirty();
150       ctrl.updateValueAndValidity();
151     };
152
153     it('should test hideModal', () => {
154       expect(component.hideModal).toBeTruthy();
155       spyOn(component, 'closeModal').and.callThrough();
156       expect(component.closeModal).not.toHaveBeenCalled();
157       component.hideModal();
158       expect(component.closeModal).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(true, 'required', true);
175         component.deletionForm.reset();
176         changeValue(true);
177         changeValue(false);
178         testValidation(true, 'required', true);
179       });
180     });
181
182     describe('deletion call', () => {
183       beforeEach(() => {
184         spyOn(component, 'stopLoadingSpinner').and.callThrough();
185         spyOn(component, 'hideModal').and.callThrough();
186       });
187
188       describe('Controller driven', () => {
189         beforeEach(() => {
190           spyOn(component, 'submitAction').and.callThrough();
191           spyOn(mockComponent.ctrlRef, 'close').and.callThrough();
192         });
193
194         it('should test fake deletion that closes modal', fakeAsync(() => {
195           // Before deletionCall
196           expect(component.submitAction).not.toHaveBeenCalled();
197           // During deletionCall
198           component.callSubmitAction();
199           expect(component.stopLoadingSpinner).not.toHaveBeenCalled();
200           expect(component.hideModal).not.toHaveBeenCalled();
201           expect(mockComponent.ctrlRef.close).not.toHaveBeenCalled();
202           expect(component.submitAction).toHaveBeenCalled();
203           expect(mockComponent.finished).toBe(undefined);
204           // After deletionCall
205           tick(2000);
206           expect(component.hideModal).not.toHaveBeenCalled();
207           expect(mockComponent.ctrlRef.close).toHaveBeenCalled();
208           expect(mockComponent.finished).toEqual([6, 7, 8, 9]);
209         }));
210       });
211
212       describe('Modal driven', () => {
213         beforeEach(() => {
214           mockComponent.openModalDriven();
215           spyOn(component, 'stopLoadingSpinner').and.callThrough();
216           spyOn(component, 'hideModal').and.callThrough();
217           spyOn(mockComponent, 'fakeDelete').and.callThrough();
218         });
219
220         it('should delete and close modal', fakeAsync(() => {
221           // During deletionCall
222           component.callSubmitAction();
223           expect(mockComponent.finished).toBe(undefined);
224           expect(component.hideModal).not.toHaveBeenCalled();
225           // After deletionCall
226           tick(2000);
227           expect(mockComponent.finished).toEqual([6, 7, 8, 9]);
228           expect(component.stopLoadingSpinner).not.toHaveBeenCalled();
229           expect(component.hideModal).toHaveBeenCalled();
230         }));
231       });
232     });
233   });
234 });