]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
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'; | |
11fdf7f2 | 4 | |
f67539c2 | 5 | import { NgbActiveModal, NgbModalModule, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; |
11fdf7f2 TL |
6 | import { Observable, Subscriber, timer as observableTimer } from 'rxjs'; |
7 | ||
f67539c2 TL |
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'; | |
11fdf7f2 TL |
13 | import { CriticalConfirmationModalComponent } from './critical-confirmation-modal.component'; |
14 | ||
f67539c2 | 15 | @NgModule({}) |
11fdf7f2 TL |
16 | export class MockModule {} |
17 | ||
18 | @Component({ | |
19 | template: ` | |
f67539c2 | 20 | <button type="button" class="btn btn-danger" (click)="openCtrlDriven()"> |
9f95a23c | 21 | <i class="fa fa-times"></i>Deletion Ctrl-Test |
11fdf7f2 TL |
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 | ||
f67539c2 | 28 | <button type="button" class="btn btn-danger" (click)="openModalDriven()"> |
9f95a23c | 29 | <i class="fa fa-times"></i>Deletion Modal-Test |
11fdf7f2 TL |
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 { | |
9f95a23c | 37 | @ViewChild('ctrlDescription', { static: true }) |
11fdf7f2 | 38 | ctrlDescription: TemplateRef<any>; |
9f95a23c | 39 | @ViewChild('modalDescription', { static: true }) |
11fdf7f2 TL |
40 | modalDescription: TemplateRef<any>; |
41 | someData = [1, 2, 3, 4, 5]; | |
42 | finished: number[]; | |
f67539c2 TL |
43 | ctrlRef: NgbModalRef; |
44 | modalRef: NgbModalRef; | |
11fdf7f2 TL |
45 | |
46 | // Normally private - public was needed for the tests | |
f67539c2 | 47 | constructor(public modalService: ModalService) {} |
11fdf7f2 TL |
48 | |
49 | openCtrlDriven() { | |
50 | this.ctrlRef = this.modalService.show(CriticalConfirmationModalComponent, { | |
f67539c2 TL |
51 | submitAction: this.fakeDeleteController.bind(this), |
52 | bodyTemplate: this.ctrlDescription | |
11fdf7f2 TL |
53 | }); |
54 | } | |
55 | ||
56 | openModalDriven() { | |
57 | this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, { | |
f67539c2 TL |
58 | submitActionObservable: this.fakeDelete(), |
59 | bodyTemplate: this.modalDescription | |
11fdf7f2 TL |
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(); | |
f67539c2 | 81 | this.ctrlRef.close(); |
11fdf7f2 TL |
82 | }); |
83 | } | |
84 | } | |
85 | ||
86 | describe('CriticalConfirmationModalComponent', () => { | |
87 | let mockComponent: MockComponent; | |
88 | let component: CriticalConfirmationModalComponent; | |
89 | let mockFixture: ComponentFixture<MockComponent>; | |
11fdf7f2 | 90 | |
f67539c2 TL |
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 | ); | |
11fdf7f2 TL |
105 | |
106 | beforeEach(() => { | |
107 | mockFixture = TestBed.createComponent(MockComponent); | |
108 | mockComponent = mockFixture.componentInstance; | |
11fdf7f2 | 109 | spyOn(mockComponent.modalService, 'show').and.callFake((_modalComp, config) => { |
9f95a23c | 110 | const data = modalServiceShow(CriticalConfirmationModalComponent, config); |
f67539c2 TL |
111 | component = data.componentInstance; |
112 | return data; | |
11fdf7f2 TL |
113 | }); |
114 | mockComponent.openCtrlDriven(); | |
115 | mockFixture.detectChanges(); | |
116 | }); | |
117 | ||
118 | it('should create', () => { | |
119 | expect(component).toBeTruthy(); | |
120 | }); | |
121 | ||
11fdf7f2 TL |
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', () => { | |
9f95a23c | 144 | const changeValue = (value: boolean) => { |
11fdf7f2 TL |
145 | const ctrl = component.deletionForm.get('confirmation'); |
146 | ctrl.setValue(value); | |
147 | ctrl.markAsDirty(); | |
148 | ctrl.updateValueAndValidity(); | |
f67539c2 | 149 | mockFixture.detectChanges(); |
11fdf7f2 TL |
150 | }; |
151 | ||
152 | it('should test hideModal', () => { | |
f67539c2 | 153 | expect(component.activeModal).toBeTruthy(); |
11fdf7f2 | 154 | expect(component.hideModal).toBeTruthy(); |
f67539c2 TL |
155 | spyOn(component.activeModal, 'close').and.callThrough(); |
156 | expect(component.activeModal.close).not.toHaveBeenCalled(); | |
11fdf7f2 | 157 | component.hideModal(); |
f67539c2 | 158 | expect(component.activeModal.close).toHaveBeenCalled(); |
11fdf7f2 TL |
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(); | |
f67539c2 | 192 | spyOn(mockComponent.ctrlRef, 'close').and.callThrough(); |
11fdf7f2 TL |
193 | }); |
194 | ||
801d1391 | 195 | it('should test fake deletion that closes modal', fakeAsync(() => { |
11fdf7f2 TL |
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(); | |
f67539c2 | 202 | expect(mockComponent.ctrlRef.close).not.toHaveBeenCalled(); |
11fdf7f2 TL |
203 | expect(component.submitAction).toHaveBeenCalled(); |
204 | expect(mockComponent.finished).toBe(undefined); | |
205 | // After deletionCall | |
206 | tick(2000); | |
207 | expect(component.hideModal).not.toHaveBeenCalled(); | |
f67539c2 | 208 | expect(mockComponent.ctrlRef.close).toHaveBeenCalled(); |
11fdf7f2 TL |
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 | ||
801d1391 | 221 | it('should delete and close modal', fakeAsync(() => { |
11fdf7f2 TL |
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 | }); |