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';
5 import { BsModalRef, BsModalService, ModalModule } from 'ngx-bootstrap';
6 import { Observable, Subscriber, timer as observableTimer } from 'rxjs';
8 import { configureTestBed } from '../../unit-test-helper';
9 import { DeletionModalComponent } from './deletion-modal.component';
12 entryComponents: [DeletionModalComponent]
14 export class MockModule {}
19 class="btn btn-sm btn-primary"
20 (click)="openCtrlDriven()">
21 <i class="fa fa-fw fa-trash"></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.
29 class="btn btn-sm btn-primary"
30 (click)="openModalDriven()">
31 <i class="fa fa-fw fa-trash"></i>Deletion Modal-Test
32 <ng-template #modalDescription>
33 The spinner is handled by the modal if your given deletion function returns a Observable.
39 @ViewChild('ctrlDescription') ctrlDescription: TemplateRef<any>;
40 @ViewChild('modalDescription') modalDescription: TemplateRef<any>;
41 someData = [1, 2, 3, 4, 5];
46 // Normally private - public was needed for the tests
47 constructor(public modalService: BsModalService) {}
50 this.ctrlRef = this.modalService.show(DeletionModalComponent);
51 this.ctrlRef.content.setUp({
52 metaType: 'Controller delete handling',
54 deletionMethod: this.fakeDeleteController.bind(this),
55 description: this.ctrlDescription,
56 modalRef: this.ctrlRef
61 this.modalRef = this.modalService.show(DeletionModalComponent);
62 this.modalRef.content.setUp({
63 metaType: 'Modal delete handling',
64 pattern: 'modal-test',
65 deletionObserver: this.fakeDelete(),
66 description: this.modalDescription,
67 modalRef: this.modalRef
72 this.finished = [6, 7, 8, 9];
76 return (): Observable<any> => {
77 return new Observable((observer: Subscriber<any>) => {
78 observableTimer(100).subscribe(() => {
79 observer.next(this.finish());
86 fakeDeleteController() {
87 observableTimer(100).subscribe(() => {
94 describe('DeletionModalComponent', () => {
95 let mockComponent: MockComponent;
96 let component: DeletionModalComponent;
97 let mockFixture: ComponentFixture<MockComponent>;
98 let fixture: ComponentFixture<DeletionModalComponent>;
101 declarations: [MockComponent, DeletionModalComponent],
102 schemas: [NO_ERRORS_SCHEMA],
103 imports: [ModalModule.forRoot(), ReactiveFormsModule, MockModule]
107 mockFixture = TestBed.createComponent(MockComponent);
108 mockComponent = mockFixture.componentInstance;
109 // Mocking the modals as a lot would be left over
110 spyOn(mockComponent.modalService, 'show').and.callFake(() => {
111 const ref = new BsModalRef();
112 fixture = TestBed.createComponent(DeletionModalComponent);
113 component = fixture.componentInstance;
114 fixture.detectChanges();
115 ref.content = component;
118 mockComponent.openCtrlDriven();
119 mockFixture.detectChanges();
122 it('should create', () => {
123 expect(component).toBeTruthy();
126 describe('setUp', () => {
127 const clearSetup = () => {
128 component.metaType = undefined;
129 component.pattern = 'yes';
130 component.deletionObserver = undefined;
131 component.description = undefined;
132 component.modalRef = undefined;
135 const expectSetup = (
142 expect(component.modalRef).toBeTruthy();
143 expect(component.metaType).toBe(metaType);
144 expect(!!component.deletionObserver).toBe(observer);
145 expect(!!component.deletionMethod).toBe(method);
146 expect(component.pattern).toBe(pattern);
147 expect(!!component.description).toBe(template);
154 it('should throw error if no modal reference is given', () => {
160 ).toThrowError('No modal reference');
163 it('should throw error if no meta type is given', () => {
167 modalRef: mockComponent.ctrlRef
169 ).toThrowError('No meta type');
172 it('should throw error if no deletion method is given', () => {
176 modalRef: mockComponent.ctrlRef
178 ).toThrowError('No deletion method');
181 it('should throw no errors if metaType, modalRef and a deletion method were given', () => {
183 metaType: 'Observer',
184 modalRef: mockComponent.ctrlRef,
185 deletionObserver: mockComponent.fakeDelete()
187 expectSetup('Observer', true, false, 'yes', false);
190 metaType: 'Controller',
191 modalRef: mockComponent.ctrlRef,
192 deletionMethod: mockComponent.fakeDeleteController
194 expectSetup('Controller', false, true, 'yes', false);
197 it('should test optional parameters - pattern and description', () => {
199 metaType: 'Pattern only',
200 modalRef: mockComponent.ctrlRef,
201 deletionObserver: mockComponent.fakeDelete(),
202 pattern: '{sth/!$_8()'
204 expectSetup('Pattern only', true, false, '{sth/!$_8()', false);
207 metaType: 'Description only',
208 modalRef: mockComponent.ctrlRef,
209 deletionObserver: mockComponent.fakeDelete(),
210 description: mockComponent.modalDescription
212 expectSetup('Description only', true, false, 'yes', true);
215 metaType: 'Description and pattern',
216 modalRef: mockComponent.ctrlRef,
217 deletionObserver: mockComponent.fakeDelete(),
218 description: mockComponent.modalDescription,
219 pattern: '{sth/!$_8()'
221 expectSetup('Description and pattern', true, false, '{sth/!$_8()', true);
225 it('should test if the ctrl driven mock is set correctly through mock component', () => {
226 expect(component.metaType).toBe('Controller delete handling');
227 expect(component.pattern).toBe('ctrl-test');
228 expect(component.description).toBeTruthy();
229 expect(component.modalRef).toBeTruthy();
230 expect(component.deletionMethod).toBeTruthy();
231 expect(component.deletionObserver).not.toBeTruthy();
234 it('should test if the modal driven mock is set correctly through mock component', () => {
235 mockComponent.openModalDriven();
236 expect(component.metaType).toBe('Modal delete handling');
237 expect(component.pattern).toBe('modal-test');
238 expect(component.description).toBeTruthy();
239 expect(component.modalRef).toBeTruthy();
240 expect(component.deletionObserver).toBeTruthy();
241 expect(component.deletionMethod).not.toBeTruthy();
244 describe('component functions', () => {
245 const changeValue = (value) => {
246 component.confirmation.setValue(value);
247 component.confirmation.markAsDirty();
248 component.confirmation.updateValueAndValidity();
249 fixture.detectChanges();
252 it('should test hideModal', () => {
253 expect(component.modalRef).toBeTruthy();
254 expect(component.hideModal).toBeTruthy();
255 spyOn(component.modalRef, 'hide').and.callThrough();
256 expect(component.modalRef.hide).not.toHaveBeenCalled();
257 component.hideModal();
258 expect(component.modalRef.hide).toHaveBeenCalled();
261 describe('validate confirmation', () => {
262 const testValidation = (submitted: boolean, error: string, expected: boolean) => {
264 component.deletionForm.showError('confirmation', <NgForm>{ submitted: submitted }, error)
269 component.deletionForm.reset();
272 it('should test empty values', () => {
273 component.deletionForm.reset();
274 testValidation(false, undefined, false);
275 testValidation(true, 'required', true);
276 component.deletionForm.reset();
277 changeValue('let-me-pass');
279 testValidation(true, 'required', true);
282 it('should test pattern', () => {
283 changeValue('let-me-pass');
284 testValidation(false, 'pattern', true);
285 changeValue('ctrl-test');
286 testValidation(false, undefined, false);
287 testValidation(true, undefined, false);
291 describe('deletion call', () => {
293 spyOn(component, 'stopLoadingSpinner').and.callThrough();
294 spyOn(component, 'hideModal').and.callThrough();
297 describe('Controller driven', () => {
299 spyOn(component, 'deletionMethod').and.callThrough();
300 spyOn(mockComponent.ctrlRef, 'hide').and.callThrough();
303 it('should test fake deletion that closes modal', <any>fakeAsync(() => {
304 // Before deletionCall
305 expect(component.deletionMethod).not.toHaveBeenCalled();
306 // During deletionCall
307 component.deletionCall();
308 expect(component.stopLoadingSpinner).not.toHaveBeenCalled();
309 expect(component.hideModal).not.toHaveBeenCalled();
310 expect(mockComponent.ctrlRef.hide).not.toHaveBeenCalled();
311 expect(component.deletionMethod).toHaveBeenCalled();
312 expect(mockComponent.finished).toBe(undefined);
313 // After deletionCall
315 expect(component.hideModal).not.toHaveBeenCalled();
316 expect(mockComponent.ctrlRef.hide).toHaveBeenCalled();
317 expect(mockComponent.finished).toEqual([6, 7, 8, 9]);
321 describe('Modal driven', () => {
323 mockComponent.openModalDriven();
324 spyOn(mockComponent.modalRef, 'hide').and.callThrough();
325 spyOn(component, 'stopLoadingSpinner').and.callThrough();
326 spyOn(component, 'hideModal').and.callThrough();
327 spyOn(mockComponent, 'fakeDelete').and.callThrough();
330 it('should delete and close modal', <any>fakeAsync(() => {
331 // During deletionCall
332 component.deletionCall();
333 expect(mockComponent.finished).toBe(undefined);
334 expect(component.hideModal).not.toHaveBeenCalled();
335 expect(mockComponent.modalRef.hide).not.toHaveBeenCalled();
336 // After deletionCall
338 expect(mockComponent.finished).toEqual([6, 7, 8, 9]);
339 expect(mockComponent.modalRef.hide).toHaveBeenCalled();
340 expect(component.stopLoadingSpinner).not.toHaveBeenCalled();
341 expect(component.hideModal).toHaveBeenCalled();