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 '../../../../testing/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')
40 ctrlDescription: TemplateRef<any>;
41 @ViewChild('modalDescription')
42 modalDescription: TemplateRef<any>;
43 someData = [1, 2, 3, 4, 5];
48 // Normally private - public was needed for the tests
49 constructor(public modalService: BsModalService) {}
52 this.ctrlRef = this.modalService.show(DeletionModalComponent);
53 this.ctrlRef.content.setUp({
54 metaType: 'Controller delete handling',
56 deletionMethod: this.fakeDeleteController.bind(this),
57 description: this.ctrlDescription,
58 modalRef: this.ctrlRef
63 this.modalRef = this.modalService.show(DeletionModalComponent);
64 this.modalRef.content.setUp({
65 metaType: 'Modal delete handling',
66 pattern: 'modal-test',
67 deletionObserver: this.fakeDelete(),
68 description: this.modalDescription,
69 modalRef: this.modalRef
74 this.finished = [6, 7, 8, 9];
78 return (): Observable<any> => {
79 return new Observable((observer: Subscriber<any>) => {
80 observableTimer(100).subscribe(() => {
81 observer.next(this.finish());
88 fakeDeleteController() {
89 observableTimer(100).subscribe(() => {
96 describe('DeletionModalComponent', () => {
97 let mockComponent: MockComponent;
98 let component: DeletionModalComponent;
99 let mockFixture: ComponentFixture<MockComponent>;
100 let fixture: ComponentFixture<DeletionModalComponent>;
103 declarations: [MockComponent, DeletionModalComponent],
104 schemas: [NO_ERRORS_SCHEMA],
105 imports: [ModalModule.forRoot(), ReactiveFormsModule, MockModule]
109 mockFixture = TestBed.createComponent(MockComponent);
110 mockComponent = mockFixture.componentInstance;
111 // Mocking the modals as a lot would be left over
112 spyOn(mockComponent.modalService, 'show').and.callFake(() => {
113 const ref = new BsModalRef();
114 fixture = TestBed.createComponent(DeletionModalComponent);
115 component = fixture.componentInstance;
116 fixture.detectChanges();
117 ref.content = component;
120 mockComponent.openCtrlDriven();
121 mockFixture.detectChanges();
124 it('should create', () => {
125 expect(component).toBeTruthy();
128 describe('setUp', () => {
129 const clearSetup = () => {
130 component.metaType = undefined;
131 component.pattern = 'yes';
132 component.deletionObserver = undefined;
133 component.description = undefined;
134 component.modalRef = undefined;
137 const expectSetup = (
144 expect(component.modalRef).toBeTruthy();
145 expect(component.metaType).toBe(metaType);
146 expect(!!component.deletionObserver).toBe(observer);
147 expect(!!component.deletionMethod).toBe(method);
148 expect(component.pattern).toBe(pattern);
149 expect(!!component.description).toBe(template);
156 it('should throw error if no modal reference is given', () => {
162 ).toThrowError('No modal reference');
165 it('should throw error if no meta type is given', () => {
169 modalRef: mockComponent.ctrlRef
171 ).toThrowError('No meta type');
174 it('should throw error if no deletion method is given', () => {
178 modalRef: mockComponent.ctrlRef
180 ).toThrowError('No deletion method');
183 it('should throw no errors if metaType, modalRef and a deletion method were given', () => {
185 metaType: 'Observer',
186 modalRef: mockComponent.ctrlRef,
187 deletionObserver: mockComponent.fakeDelete()
189 expectSetup('Observer', true, false, 'yes', false);
192 metaType: 'Controller',
193 modalRef: mockComponent.ctrlRef,
194 deletionMethod: mockComponent.fakeDeleteController
196 expectSetup('Controller', false, true, 'yes', false);
199 it('should test optional parameters - pattern and description', () => {
201 metaType: 'Pattern only',
202 modalRef: mockComponent.ctrlRef,
203 deletionObserver: mockComponent.fakeDelete(),
204 pattern: '{sth/!$_8()'
206 expectSetup('Pattern only', true, false, '{sth/!$_8()', false);
209 metaType: 'Description only',
210 modalRef: mockComponent.ctrlRef,
211 deletionObserver: mockComponent.fakeDelete(),
212 description: mockComponent.modalDescription
214 expectSetup('Description only', true, false, 'yes', true);
217 metaType: 'Description and pattern',
218 modalRef: mockComponent.ctrlRef,
219 deletionObserver: mockComponent.fakeDelete(),
220 description: mockComponent.modalDescription,
221 pattern: '{sth/!$_8()'
223 expectSetup('Description and pattern', true, false, '{sth/!$_8()', true);
227 it('should test if the ctrl driven mock is set correctly through mock component', () => {
228 expect(component.metaType).toBe('Controller delete handling');
229 expect(component.pattern).toBe('ctrl-test');
230 expect(component.description).toBeTruthy();
231 expect(component.modalRef).toBeTruthy();
232 expect(component.deletionMethod).toBeTruthy();
233 expect(component.deletionObserver).not.toBeTruthy();
236 it('should test if the modal driven mock is set correctly through mock component', () => {
237 mockComponent.openModalDriven();
238 expect(component.metaType).toBe('Modal delete handling');
239 expect(component.pattern).toBe('modal-test');
240 expect(component.description).toBeTruthy();
241 expect(component.modalRef).toBeTruthy();
242 expect(component.deletionObserver).toBeTruthy();
243 expect(component.deletionMethod).not.toBeTruthy();
246 describe('component functions', () => {
247 const changeValue = (value) => {
248 component.confirmation.setValue(value);
249 component.confirmation.markAsDirty();
250 component.confirmation.updateValueAndValidity();
251 fixture.detectChanges();
254 it('should test hideModal', () => {
255 expect(component.modalRef).toBeTruthy();
256 expect(component.hideModal).toBeTruthy();
257 spyOn(component.modalRef, 'hide').and.callThrough();
258 expect(component.modalRef.hide).not.toHaveBeenCalled();
259 component.hideModal();
260 expect(component.modalRef.hide).toHaveBeenCalled();
263 describe('validate confirmation', () => {
264 const testValidation = (submitted: boolean, error: string, expected: boolean) => {
266 component.deletionForm.showError('confirmation', <NgForm>{ submitted: submitted }, error)
271 component.deletionForm.reset();
274 it('should test empty values', () => {
275 component.deletionForm.reset();
276 testValidation(false, undefined, false);
277 testValidation(true, 'required', true);
278 component.deletionForm.reset();
279 changeValue('let-me-pass');
281 testValidation(true, 'required', true);
284 it('should test pattern', () => {
285 changeValue('let-me-pass');
286 testValidation(false, 'pattern', true);
287 changeValue('ctrl-test');
288 testValidation(false, undefined, false);
289 testValidation(true, undefined, false);
292 it('should test regex pattern', () => {
293 component.pattern = 'a+b';
295 testValidation(false, 'pattern', true);
297 testValidation(false, 'pattern', false);
301 describe('deletion call', () => {
303 spyOn(component, 'stopLoadingSpinner').and.callThrough();
304 spyOn(component, 'hideModal').and.callThrough();
307 describe('Controller driven', () => {
309 spyOn(component, 'deletionMethod').and.callThrough();
310 spyOn(mockComponent.ctrlRef, 'hide').and.callThrough();
313 it('should test fake deletion that closes modal', <any>fakeAsync(() => {
314 // Before deletionCall
315 expect(component.deletionMethod).not.toHaveBeenCalled();
316 // During deletionCall
317 component.deletionCall();
318 expect(component.stopLoadingSpinner).not.toHaveBeenCalled();
319 expect(component.hideModal).not.toHaveBeenCalled();
320 expect(mockComponent.ctrlRef.hide).not.toHaveBeenCalled();
321 expect(component.deletionMethod).toHaveBeenCalled();
322 expect(mockComponent.finished).toBe(undefined);
323 // After deletionCall
325 expect(component.hideModal).not.toHaveBeenCalled();
326 expect(mockComponent.ctrlRef.hide).toHaveBeenCalled();
327 expect(mockComponent.finished).toEqual([6, 7, 8, 9]);
331 describe('Modal driven', () => {
333 mockComponent.openModalDriven();
334 spyOn(mockComponent.modalRef, 'hide').and.callThrough();
335 spyOn(component, 'stopLoadingSpinner').and.callThrough();
336 spyOn(component, 'hideModal').and.callThrough();
337 spyOn(mockComponent, 'fakeDelete').and.callThrough();
340 it('should delete and close modal', <any>fakeAsync(() => {
341 // During deletionCall
342 component.deletionCall();
343 expect(mockComponent.finished).toBe(undefined);
344 expect(component.hideModal).not.toHaveBeenCalled();
345 expect(mockComponent.modalRef.hide).not.toHaveBeenCalled();
346 // After deletionCall
348 expect(mockComponent.finished).toEqual([6, 7, 8, 9]);
349 expect(mockComponent.modalRef.hide).toHaveBeenCalled();
350 expect(component.stopLoadingSpinner).not.toHaveBeenCalled();
351 expect(component.hideModal).toHaveBeenCalled();