From 72699d3a6de8f55f6df8dbb3e00db62b6e3aebd6 Mon Sep 17 00:00:00 2001 From: Morgan Touverey Quilling Date: Fri, 10 Apr 2020 11:10:31 +0200 Subject: [PATCH] feat(SwalComponent): allow user to pass native hooks as well (fixes #159) --- .../src/lib/swal.component.spec.ts | 73 +++++++++++++++++-- .../ngx-sweetalert2/src/lib/swal.component.ts | 39 ++++++---- tslint.json | 3 +- 3 files changed, 94 insertions(+), 21 deletions(-) diff --git a/projects/ngx-sweetalert2/src/lib/swal.component.spec.ts b/projects/ngx-sweetalert2/src/lib/swal.component.spec.ts index bc0a639..bee022e 100644 --- a/projects/ngx-sweetalert2/src/lib/swal.component.spec.ts +++ b/projects/ngx-sweetalert2/src/lib/swal.component.spec.ts @@ -1,18 +1,26 @@ +import { SimpleChange } from '@angular/core'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import OriginalSwal from 'sweetalert2'; import { dismissOnDestroyToken, fireOnInitToken, swalProviderToken } from './di'; - import { SwalComponent } from './swal.component'; import { SweetAlert2LoaderService } from './sweetalert2-loader.service'; -describe('NgxSweetalert2Component', () => { +/* tslint:disable:no-lifecycle-call max-classes-per-file */ + +describe('SwalComponent', () => { + let swal: typeof OriginalSwal; let component: SwalComponent; let fixture: ComponentFixture; + const testTitle = 'Test title'; + const testText = 'Test text'; beforeEach(async(() => { + swal = jasmine.createSpyObj(['fire']); + TestBed.configureTestingModule({ providers: [ SweetAlert2LoaderService, - { provide: swalProviderToken, useValue: () => import('sweetalert2') }, + { provide: swalProviderToken, useValue: swal }, { provide: fireOnInitToken, useValue: false }, { provide: dismissOnDestroyToken, useValue: true } ], @@ -28,7 +36,62 @@ describe('NgxSweetalert2Component', () => { fixture.detectChanges(); }); - it('should create', () => { - expect(component).toBeTruthy(); + it('should not print anything into the DOM', () => { + expect(fixture.nativeElement.innerHTML).toBe(''); + }); + + it('should not have default options', () => { + const optionsKeys = Object.keys(component.swalOptions); + + expect(optionsKeys.length).toBe(0); + }); + + it('should convert @Inputs to swal options', () => { + component.title = testTitle; + component.ngOnChanges({ title: new SimpleChange(null, testTitle, true) }); + + component.text = testText; + component.ngOnChanges({ text: new SimpleChange(null, testText, true) }); + + const { title, text, ...rest } = component.swalOptions; + + expect(title).toBe(testTitle); + expect(text).toBe(testText); + + expect(Object.keys(rest).length).toBe(0); + }); + + it('should merge options set via swalOptions with the current ones', () => { + component.title = testTitle; + component.text = testText; + component.ngOnChanges({ + title: new SimpleChange(null, testTitle, true), + text: new SimpleChange(null, testText, true) + }); + + component.swalOptions = { title: `# ${testTitle}`, icon: 'question' }; + + const { title, text, icon } = component.swalOptions; + + expect(title).toBe(`# ${testTitle}`); + expect(text).toBe(testText); + expect(icon).toBe('question'); + }); + + it('should not copy special properties to the swal options object', () => { + component.swalFireOnInit = false; + component.swalDismissOnDestroy = false; + component.swalVisible = false; + + component.ngOnChanges({ + swalFireOnInit: new SimpleChange(null, false, true), + swalDismissOnDestroy: new SimpleChange(null, false, true), + swalVisible: new SimpleChange(null, false, true) + }); + + const optionsKeys = Object.keys(component.swalOptions); + + expect(optionsKeys.filter(key => key.startsWith('swal')).length).toBe(0); }); }); + diff --git a/projects/ngx-sweetalert2/src/lib/swal.component.ts b/projects/ngx-sweetalert2/src/lib/swal.component.ts index 7519549..1d2c981 100644 --- a/projects/ngx-sweetalert2/src/lib/swal.component.ts +++ b/projects/ngx-sweetalert2/src/lib/swal.component.ts @@ -1,6 +1,6 @@ import { - AfterViewInit, - ChangeDetectionStrategy, Component, EventEmitter, Inject, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges + AfterViewInit, ChangeDetectionStrategy, Component, EventEmitter, Inject, Input, OnChanges, OnDestroy, OnInit, + Output, SimpleChanges } from '@angular/core'; import Swal, { SweetAlertOptions, SweetAlertResult } from 'sweetalert2'; import { dismissOnDestroyToken, fireOnInitToken } from './di'; @@ -317,32 +317,34 @@ export class SwalComponent implements OnInit, AfterViewInit, OnChanges, OnDestro public async fire(): Promise { const swal = await this.sweetAlert2Loader.swal; + const userOptions = this.swalOptions; + //=> Build the SweetAlert2 options const options: SweetAlertOptions = { //=> Merge with calculated options set for that specific swal - ...this.swalOptions, + ...userOptions, //=> Handle modal lifecycle events - onBeforeOpen: (modalElement) => { + onBeforeOpen: composeHook(userOptions.onBeforeOpen, (modalElement) => { this.beforeOpen.emit({ modalElement }); - }, - onOpen: (modalElement) => { + }), + onOpen: composeHook(userOptions.onOpen, (modalElement) => { this.isCurrentlyShown = true; this.open.emit({ modalElement }); - }, - onRender: (modalElement) => { + }), + onRender: composeHook(userOptions.onRender, (modalElement) => { this.render.emit({ modalElement }); - }, - onClose: (modalElement) => { + }), + onClose: composeHook(userOptions.onClose, (modalElement) => { this.isCurrentlyShown = false; this.close.emit({ modalElement }); - }, - onAfterClose: () => { + }), + onAfterClose: composeHook(userOptions.onAfterClose, () => { this.afterClose.emit(); - }, - onDestroy: () => { + }), + onDestroy: composeHook(userOptions.onDestroy, () => { this.destroy.emit(); - } + }) }; //=> Show the Swal! And wait for confirmation or dimissal. @@ -356,6 +358,13 @@ export class SwalComponent implements OnInit, AfterViewInit, OnChanges, OnDestro } return result; + + function composeHook void>( + userHook: T | undefined, + libHook: T): (...args: Parameters) => void { + + return (...args) => (libHook(...args), userHook?.(...args)); + } } /** diff --git a/tslint.json b/tslint.json index e60df0c..e43d251 100644 --- a/tslint.json +++ b/tslint.json @@ -15,6 +15,7 @@ "no-object-literal-type-assertion": false, "member-ordering": false, "no-unused-expression": false, - "array-type": [true, "array-simple"] + "array-type": [true, "array-simple"], + "ban-comma-operator": false } }