angular5-toaster
Version:
An Angular Toaster Notification library based on AngularJS-Toaster
1,070 lines (818 loc) • 40 kB
text/typescript
import {Component, NgModule} from '@angular/core';
import {TestBed} from '@angular/core/testing';
import {ComponentFixture} from '@angular/core/testing';
import {Toast, ClickHandler} from './toast';
import {ToasterService} from './toaster.service';
import {ToasterContainerComponent} from './toaster-container.component';
import {ToasterConfig} from './toaster-config';
import {BodyOutputType} from './bodyOutputType';
import {ToasterModule} from '../angular5-toaster';
import {BrowserModule} from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
// Mock component for bootstrapping <toaster-container></toaster-container>
@Component({
selector: 'test-component',
template: '<toaster-container [toasterconfig]="toasterconfig"></toaster-container>',
})
export class TestComponent {
toasterService: ToasterService;
public toasterconfig: ToasterConfig =
new ToasterConfig({ showCloseButton: true, tapToDismiss: false, timeout: 0, toastContainerId: 1 });
public toasterconfig2: ToasterConfig =
new ToasterConfig({ showCloseButton: true, tapToDismiss: false, timeout: 0, toastContainerId: 2 });
constructor(toasterService: ToasterService) {
this.toasterService = toasterService;
}
}
@NgModule({
imports: [ToasterModule, BrowserAnimationsModule],
declarations: [TestComponent]
})
export class TestComponentModule {}
// Mock component for testing bodyOutputType Component rendering
@Component({
selector: 'test-dynamic-component',
template: `<div>loaded via component</div>`
})
export class TestDynamicComponent { }
@NgModule({
bootstrap: [TestDynamicComponent],
declarations: [TestDynamicComponent]
})
export class TestDynamicComponentModule { }
@Component({
selector: 'bound-dynamic-component',
template: '<div>{{someValue}} loaded via component<button (click)="clickHandler()" id="click"></button></div>'
})
export class TestBoundDynamicComponent {
someValue = 'Some value';
public toast: Toast = null;
clickHandler() {
this.toast.title = 'updated title';
}
}
@NgModule({
bootstrap: [TestBoundDynamicComponent],
declarations: [TestBoundDynamicComponent]
})
export class TestBoundDynamicComponentModule { }
describe('ToasterContainerComponent with sync ToasterService', () => {
let toasterService: ToasterService,
toasterContainer: ToasterContainerComponent,
fixture: ComponentFixture<TestComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestComponent],
imports: [ToasterModule, BrowserModule, BrowserAnimationsModule]
});
fixture = TestBed.createComponent<TestComponent>(TestComponent);
toasterContainer = fixture.debugElement.children[0].componentInstance;
toasterService = fixture.componentInstance.toasterService;
return fixture;
});
it('should pop toast synchronously', () => {
toasterContainer.ngOnInit();
toasterService.pop('success', 'test', 'test');
expect(toasterContainer.toasts.length).toBe(1);
});
it('should pop toast asynchronously', () => {
// create test-specific fixture to protect against
// container being overwritten by other tests since this
// test now executes fully asynchronously
const fixtureInstance = TestBed.createComponent<TestComponent>(TestComponent);
const toasterContainerInstance = fixtureInstance.debugElement.children[0].componentInstance;
const toasterServiceInstance = fixtureInstance.componentInstance.toasterService;
fixtureInstance.detectChanges();
fixtureInstance.whenStable().then(() => {
toasterContainerInstance.ngOnInit();
toasterServiceInstance.popAsync('success', 'test', 'test')
.subscribe(toast => {
expect(toast).toBeDefined();
expect(toast.type).toBe('success');
expect(toasterContainerInstance.toasts.length).toBe(1);
expect(toast.toastId).toBe(toasterContainerInstance.toasts[0].toastId);
});
});
});
it('should pop toast asynchronously multiple times', () => {
// create test-specific fixture to protect against
// container being overwritten by other tests since this
// test now executes fully asynchronously
const fixtureInstance = TestBed.createComponent<TestComponent>(TestComponent);
const toasterContainerInstance = fixtureInstance.debugElement.children[0].componentInstance;
const toasterServiceInstance = fixtureInstance.componentInstance.toasterService;
fixtureInstance.detectChanges();
fixtureInstance.whenStable().then(() => {
toasterContainerInstance.ngOnInit();
toasterServiceInstance.popAsync('success', 'test', 'test');
toasterServiceInstance.popAsync('success', 'test', 'test');
toasterServiceInstance.popAsync('success', 'test', 'test')
.subscribe(toast => {
expect(toast).toBeDefined();
expect(toast.type).toBe('success');
let locatedToast;
for (let i = 0; i < toasterContainerInstance.toasts.length; i++) {
if (toasterContainerInstance.toasts[i].toastId === toast.toastId) {
locatedToast = toasterContainerInstance.toasts[i];
break;
}
}
expect(locatedToast).toBeDefined();
});
});
});
it('should retrieve toast instance from pop observer', () => {
toasterContainer.ngOnInit();
let toast: Toast = {
type: 'success',
title: 'observer toast'
};
expect(toasterContainer.toasts.length).toBe(0);
toast = toasterService.pop(toast);
expect(toast).toBeDefined();
expect(toast.type).toBe(toast.type);
expect(toast.title).toBe(toast.title);
expect(toast.toastId).toBe(toasterContainer.toasts[0].toastId);
});
it('should clear toast synchronously', () => {
toasterContainer.ngOnInit();
toasterService.pop('success', 'test', 'test');
expect(toasterContainer.toasts.length).toBe(1);
toasterService.clear();
expect(toasterContainer.toasts.length).toBe(0);
});
it('should throw exception if toast is popped without any subscribers being registered', () => {
let hasError = false;
try {
toasterService.pop('success', 'test', 'test');
} catch (e) {
hasError = true;
expect(e.message).toBe('No Toaster Containers have been initialized to receive toasts.');
}
expect(toasterContainer.toasts.length).toBe(0);
expect(hasError).toBe(true);
});
it('should remove subscribers when ngOnDestroy is called', () => {
toasterContainer.ngOnInit();
toasterService.pop('success', 'test', 'test');
expect(toasterContainer.toasts.length).toBe(1);
toasterContainer.ngOnDestroy();
toasterService.pop('success', 'test 2', 'test 2');
toasterService.clear();
expect(toasterContainer.toasts.length).toBe(1);
});
it('will not attempt to remove subscribers when ngOnDestroy is called if ngOnInit is not called', () => {
spyOn(toasterContainer, 'ngOnInit').and.callThrough();
spyOn(toasterContainer, 'ngOnDestroy').and.callThrough();
expect(toasterContainer.ngOnInit).not.toHaveBeenCalled();
toasterContainer.ngOnDestroy();
expect(toasterContainer.ngOnDestroy).toHaveBeenCalled();
});
it('stopTimer should clear timer if mouseOverTimerStop is true', () => {
toasterContainer.toasterconfig = new ToasterConfig({ mouseoverTimerStop: true, timeout: 100 });
toasterContainer.ngOnInit();
toasterService.pop('success', 'test', 'test');
const toast = toasterContainer.toasts[0];
expect(toasterContainer.toasterconfig.mouseoverTimerStop).toBe(true);
expect(toast).toBeDefined();
expect(toast.timeoutId).toBeDefined();
toasterContainer.stopTimer(toast);
expect(toast.timeoutId).toBeNull();
});
it('stopTimer should not clear timer if mouseOverTimerStop is false', () => {
toasterContainer.toasterconfig = new ToasterConfig({ timeout: 100 });
toasterContainer.ngOnInit();
toasterService.pop('success', 'test', 'test');
const toast = toasterContainer.toasts[0];
expect(toasterContainer.toasterconfig.mouseoverTimerStop).toBe(false);
expect(toast).toBeDefined();
expect(toast.timeoutId).toBeDefined();
toasterContainer.stopTimer(toast);
expect(toast.timeoutId).toBeDefined();
});
it('stopTimer should not clear timer if mouseOverTimerStop is true and timeout is 0', () => {
toasterContainer.toasterconfig = new ToasterConfig({ mouseoverTimerStop: true, timeout: 0 });
toasterContainer.ngOnInit();
toasterService.pop('success', 'test', 'test');
const toast = toasterContainer.toasts[0];
expect(toasterContainer.toasterconfig.mouseoverTimerStop).toBe(true);
expect(toast).toBeDefined();
expect(toast.timeout).toBeUndefined();
expect(toast.timeoutId).toBeUndefined();
toasterContainer.stopTimer(toast);
expect(toast.timeoutId).toBeUndefined();
});
it('restartTimer should restart timer if mouseOverTimerStop is true', () => {
toasterContainer.toasterconfig = new ToasterConfig({ mouseoverTimerStop: true, timeout: 100 });
toasterContainer.ngOnInit();
toasterService.pop('success', 'test', 'test');
const toast = toasterContainer.toasts[0];
expect(toasterContainer.toasterconfig.mouseoverTimerStop).toBe(true);
expect(toast).toBeDefined();
expect(toast.timeoutId).toBeDefined();
toasterContainer.restartTimer(toast);
expect(toast.timeoutId).toBeDefined();
});
it('restartTimer should not restart timer if mouseOverTimerStop is true and timeoutId is undefined', () => {
toasterContainer.toasterconfig = new ToasterConfig({ mouseoverTimerStop: true, timeout: 0 });
toasterContainer.ngOnInit();
toasterService.pop('success', 'test', 'test');
const toast = toasterContainer.toasts[0];
expect(toasterContainer.toasterconfig.mouseoverTimerStop).toBe(true);
expect(toast).toBeDefined();
expect(toast.timeoutId).toBeUndefined();
toasterContainer.restartTimer(toast);
expect(toast.timeoutId).toBeUndefined();
});
it('restartTimer should not restart timer if mouseOverTimerStop is false', () => {
toasterContainer.toasterconfig = new ToasterConfig({ timeout: 1 });
toasterContainer.ngOnInit();
toasterService.pop('success', 'test', 'test');
const toast = toasterContainer.toasts[0];
expect(toasterContainer.toasterconfig.mouseoverTimerStop).toBe(false);
expect(toast).toBeDefined();
expect(toast.timeoutId).toBeDefined();
toasterContainer.restartTimer(toast);
setTimeout(() => {
expect(toast.timeoutId).toBeNull();
}, 2)
});
it('restartTimer should remove toast if mouseOverTimerStop is false and timeoutId is null', () => {
toasterContainer.toasterconfig = new ToasterConfig({ timeout: 0 });
toasterContainer.ngOnInit();
toasterService.pop('success', 'test', 'test');
const toast = toasterContainer.toasts[0];
expect(toasterContainer.toasterconfig.mouseoverTimerStop).toBe(false);
expect(toast).toBeDefined();
expect(toast.timeoutId).toBeUndefined();
toast.timeoutId = null;
toasterContainer.restartTimer(toast);
expect(toasterContainer.toasts.length).toBe(0);
});
it('addToast should not add toast if toasterContainerId is provided and it does not match', () => {
toasterContainer.toasterconfig = new ToasterConfig({ toastContainerId: 2 })
const toast: Toast = { type: 'success', toastContainerId: 1 };
toasterContainer.ngOnInit();
toasterService.pop(toast);
expect(toasterContainer.toasts.length).toBe(0);
});
it('addToast should use defaultTypeClass if type is empty string', () => {
toasterContainer.ngOnInit();
toasterService.pop('', '', '');
expect(toasterContainer.toasterconfig.defaultTypeClass).toBe('toast-info');
expect(toasterContainer.toasts.length).toBe(1);
expect(toasterContainer.toasts[0].type).toBe('toast-info');
});
it('addToast should not add toast if preventDuplicates and the same toastId exists', () => {
toasterContainer.toasterconfig = new ToasterConfig({ preventDuplicates: true });
toasterContainer.ngOnInit();
const toast: Toast = { type: 'info' };
toasterService.pop(toast);
expect(toasterContainer.toasts.length).toBe(1);
toasterService.pop(toast);
expect(toasterContainer.toasts.length).toBe(1);
});
it('addToast should not add toast if preventDuplicates and toastId does not exist and the same body exists', () => {
toasterContainer.toasterconfig = new ToasterConfig({ preventDuplicates: true });
toasterContainer.ngOnInit();
const toast: Toast = { type: 'info', body: 'test' };
const toast2: Toast = { type: 'info', body: 'test2' };
const toast3: Toast = { type: 'info', body: 'test2' };
toasterService.pop(toast);
expect(toasterContainer.toasts.length).toBe(1);
toasterService.pop(toast2);
expect(toasterContainer.toasts.length).toBe(2);
toasterService.pop(toast3);
expect(toasterContainer.toasts.length).toBe(2);
});
it('addToast uses toast.showCloseButton if defined', () => {
toasterContainer.ngOnInit();
const toast: Toast = { type: 'info', showCloseButton: true };
toasterService.pop(toast);
fixture.detectChanges();
expect(toasterContainer.toasts[0].showCloseButton).toBe(true);
});
it('addToast uses toasterconfig.showCloseButton object if defined and toast.showCloseButton is undefined', () => {
toasterContainer.toasterconfig = new ToasterConfig({ showCloseButton: { 'info': true } });
toasterContainer.ngOnInit();
const toast: Toast = { type: 'info' };
const toast2: Toast = { type: 'success' };
toasterService.pop(toast);
toasterService.pop(toast2);
const infoToast = toasterContainer.toasts.filter(t => t.type === 'info')[0];
const successToast = toasterContainer.toasts.filter(t => t.type === 'success')[0];
expect(infoToast.showCloseButton).toBe(true);
expect(successToast.showCloseButton).toBeUndefined();
});
it('addToast uses toast.showCloseButton if defined', () => {
toasterContainer.toasterconfig = new ToasterConfig({ showCloseButton: '' });
toasterContainer.ngOnInit();
const toast: Toast = { type: 'info' };
toasterService.pop(toast);
expect(toasterContainer.toasts[0].showCloseButton).toBeUndefined();
});
it('addToast removes toast from bottom if toasterconfig.newestOnTop and limit exceeded', () => {
toasterContainer.toasterconfig = new ToasterConfig({ limit: 2 });
toasterContainer.ngOnInit();
expect(toasterContainer.toasterconfig.newestOnTop).toBe(true);
expect(toasterContainer.toasterconfig.limit).toBe(2);
const toast1: Toast = { type: 'info', title: '1', body: '1' };
const toast2: Toast = { type: 'info', title: '2', body: '2' };
const toast3: Toast = { type: 'info', title: '3', body: '3' };
const toast4: Toast = { type: 'info', title: '4', body: '4' };
toasterService.pop(toast1);
toasterService.pop(toast2);
toasterService.pop(toast3);
toasterService.pop(toast4);
expect(toasterContainer.toasts.length).toBe(2);
expect(toasterContainer.toasts[0].title).toBe('4');
expect(toasterContainer.toasts[0]).toBe(toast4);
});
it('addToast will not populate safeCloseHtml if closeHtml is null', () => {
toasterContainer.toasterconfig = new ToasterConfig();
toasterContainer.toasterconfig.closeHtml = null;
toasterContainer.ngOnInit();
const toast1: Toast = { type: 'info', title: '1', body: '1', showCloseButton: true };
toasterService.pop(toast1);
fixture.detectChanges();
const closeButtonEle = fixture.nativeElement.querySelector('.toast-close-button');
expect(closeButtonEle.innerHTML).toBe('');
});
it('addToast will populate safeCloseHtml with default html', () => {
toasterContainer.toasterconfig = new ToasterConfig();
toasterContainer.ngOnInit();
const toast1: Toast = { type: 'info', title: '1', body: '1', showCloseButton: true };
toasterService.pop(toast1);
fixture.detectChanges();
const closeButtonEle = fixture.nativeElement.querySelector('.toast-close-button');
expect(closeButtonEle.innerHTML).toBe('<button class="toast-close-button" type="button">×</button>');
});
it('addToast removes toast from top if !toasterconfig.newestOnTop and limit exceeded', () => {
toasterContainer.toasterconfig = new ToasterConfig({ newestOnTop: false, limit: 2 });
toasterContainer.ngOnInit();
expect(toasterContainer.toasterconfig.newestOnTop).toBe(false);
expect(toasterContainer.toasterconfig.limit).toBe(2);
const toast1: Toast = { type: 'info', title: '1', body: '1' };
const toast2: Toast = { type: 'info', title: '2', body: '2' };
const toast3: Toast = { type: 'info', title: '3', body: '3' };
const toast4: Toast = { type: 'info', title: '4', body: '4' };
toasterService.pop(toast1);
toasterService.pop(toast2);
toasterService.pop(toast3);
toasterService.pop(toast4);
expect(toasterContainer.toasts.length).toBe(2);
expect(toasterContainer.toasts[0].title).toBe('3');
expect(toasterContainer.toasts[0]).toBe(toast3);
});
it('addToast calls onShowCallback if it exists', () => {
toasterContainer.ngOnInit();
const toast: Toast = { type: 'info', title: 'default', onShowCallback: (toaster) => toaster.title = 'updated' };
toasterService.pop(toast);
expect(toasterContainer.toasts[0].title).toBe('updated');
});
it('addToast registers timeout callback if timeout is greater than 0', () => {
toasterContainer.toasterconfig = new ToasterConfig({ timeout: 1 });
toasterContainer.ngOnInit();
const toast = toasterService.pop('success');
expect(toast.timeoutId).toBeDefined();
expect(toasterContainer.toasts.length).toBe(1);
setTimeout(() => {
fixture.whenStable().then(() => {
expect(toasterContainer.toasts.length).toBe(0);
expect(toast.timeoutId).toBeNull();
});
}, 2);
});
it('addToast will not register timeout callback if toast.timeout is 0', () => {
toasterContainer.toasterconfig = new ToasterConfig({ timeout: 1 });
toasterContainer.ngOnInit();
const toast: Toast = { type: 'success', timeout: 0 };
const poppedToast = toasterService.pop(toast);
expect(poppedToast.timeoutId).toBeUndefined();
});
it('addToast will fallback to toasterconfig timeout value if toast.timeout is undefined', () => {
toasterContainer.toasterconfig = new ToasterConfig({ timeout: 1 });
toasterContainer.ngOnInit();
const toast: Toast = { type: 'success' };
const poppedToast = toasterService.pop(toast);
expect(poppedToast.timeoutId).toBeDefined();
expect((<any>(poppedToast.timeoutId)).data.delay).toBe(1);
});
it('addToast will not register timeout if toast.timeout is undefined and toasterconfig.timeout is 0', () => {
toasterContainer.toasterconfig = new ToasterConfig({ timeout: 0 });
toasterContainer.ngOnInit();
const toast: Toast = { type: 'success' };
const poppedToast = toasterService.pop(toast);
expect(poppedToast.timeoutId).toBeUndefined();
});
it('addToast uses toasterconfig.timeout object if defined and type exists', () => {
toasterContainer.toasterconfig = new ToasterConfig({ timeout: { 'info': 10 } });
toasterContainer.ngOnInit();
const toast: Toast = { type: 'info' };
const toast2: Toast = { type: 'success' };
toasterService.pop(toast);
toasterService.pop(toast2);
const infoToast = toasterContainer.toasts.filter(t => t.type === 'info')[0];
const successToast = toasterContainer.toasts.filter(t => t.type === 'success')[0];
expect(infoToast.timeoutId).toBeDefined();
expect(successToast.timeoutId).toBeUndefined();
});
it('removeToast will not remove the toast if it is not found in the toasters array', () => {
toasterContainer.ngOnInit();
const toast: Toast = { type: 'info' };
toasterService.pop(toast);
expect(toasterContainer.toasts.length).toBe(1);
toasterService.clear('faketoastid');
expect(toasterContainer.toasts.length).toBe(1);
});
it('removeToast calls onHideCallback if it exists', () => {
toasterContainer.ngOnInit();
let status = 'not updated';
const toast: Toast = { type: 'info', title: 'default', onHideCallback: (toastInstance) => status = 'updated' };
toasterService.pop(toast);
toasterService.clear(toast.toastId);
expect(status).toBe('updated');
});
it('removeToast notifies the removeToast subscribers', (done) => {
toasterContainer.ngOnInit();
const toast: Toast = { type: 'info', title: 'default' };
toasterService.pop(toast);
toasterService.removeToast.subscribe(t => {
expect(t.toastId).toEqual(toast.toastId);
expect(t.toastContainerId).toEqual(toast.toastContainerId);
done();
});
toasterService.clear(toast.toastId);
});
it('clearToasts will clear toasts from all containers if toastContainerId is undefined', () => {
toasterContainer.ngOnInit();
const toast: Toast = { type: 'info' };
toasterService.pop(toast);
expect(toasterContainer.toasts.length).toBe(1);
toasterService.clear(null, undefined);
expect(toasterContainer.toasts.length).toBe(0);
});
it('clearToasts will clear toasts from specified container if toastContainerId is number', () => {
toasterContainer.toasterconfig = new ToasterConfig({ toastContainerId: 1 });
toasterContainer.ngOnInit();
const toast: Toast = { type: 'info', toastContainerId: 1 };
toasterService.pop(toast);
expect(toasterContainer.toasts.length).toBe(1);
toasterService.clear(null, 1);
expect(toasterContainer.toasts.length).toBe(0);
});
it('clearToasts will not clear toasts from specified container if toastContainerId does not match', () => {
toasterContainer.toasterconfig = new ToasterConfig({ toastContainerId: 1 });
toasterContainer.ngOnInit();
const toast: Toast = { type: 'info', toastContainerId: 1 };
toasterService.pop(toast);
expect(toasterContainer.toasts.length).toBe(1);
toasterService.clear(null, 2);
expect(toasterContainer.toasts.length).toBe(1);
});
it('createGuid should create unique Guids', () => {
toasterContainer.toasterconfig = new ToasterConfig({ toastContainerId: 1 });
toasterContainer.ngOnInit();
let toastIds = [];
for (let i = 0; i < 10000; i++) {
const toast = toasterService.pop('success', 'toast');
toastIds.push(toast.toastId);
toasterService.clear();
}
let valuesSoFar = Object.create(null);
let dupFound = false;
for (let i = 0; i < toastIds.length; ++i) {
const value = toastIds[i];
if (value in valuesSoFar) {
dupFound = true;
break;
}
valuesSoFar[value] = true;
}
expect(dupFound).toBe(false);
toastIds = null;
valuesSoFar = null;
});
});
describe('ToasterContainerComponent with sync ToasterService', () => {
let toasterService: ToasterService,
toasterContainer: ToasterContainerComponent,
fixture: ComponentFixture<TestComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestComponent],
imports: [ToasterModule, BrowserModule, BrowserAnimationsModule]
});
fixture = TestBed.createComponent<TestComponent>(TestComponent);
toasterContainer = fixture.debugElement.children[0].componentInstance;
toasterService = fixture.componentInstance.toasterService;
return fixture;
});
it('addToast does not populate data if not not defined', () => {
toasterContainer.toasterconfig = new ToasterConfig();
toasterContainer.ngOnInit();
const toast: Toast = { type: 'info' };
toasterService.pop(toast);
expect(toasterContainer.toasts[0].data).toBeUndefined();
});
it('addToast sets data if type number', () => {
toasterContainer.toasterconfig = new ToasterConfig();
toasterContainer.ngOnInit();
const toast: Toast = { type: 'info', data: 1 };
toasterService.pop(toast);
expect(toasterContainer.toasts[0].data).toBe(1);
});
});
describe('ToasterContainerComponent when included as a component', () => {
let fixture: ComponentFixture<TestComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestComponent],
imports: [ToasterModule, TestDynamicComponentModule, BrowserAnimationsModule]
});
fixture = TestBed.createComponent<TestComponent>(TestComponent);
});
it('should use the bound toasterconfig object if provided', () => {
fixture.detectChanges();
expect(fixture.componentInstance).toBeDefined();
const container = fixture.debugElement.children[0].componentInstance;
expect(container).toBeDefined();
expect(container.toasterconfig).toBeDefined();
expect(container.toasterconfig.showCloseButton).toBe(true);
expect(container.toasterconfig.tapToDismiss).toBe(false);
expect(container.toasterconfig.timeout).toBe(0);
});
it('should invoke the click event when a toast is clicked but not remove toast if !tapToDismiss', () => {
fixture.detectChanges();
const container = fixture.debugElement.children[0].componentInstance;
expect(container.toasterconfig.tapToDismiss).toBe(false);
fixture.componentInstance.toasterService.pop('success', 'test', 'test');
fixture.detectChanges();
expect(container.toasts.length).toBe(1);
const toast = fixture.nativeElement.querySelector('div.toast');
toast.click();
fixture.detectChanges();
expect(container.toasts.length).toBe(1);
});
it('should invoke the click event when a toast is clicked and remove toast if tapToDismiss', () => {
fixture.componentInstance.toasterconfig.tapToDismiss = true;
fixture.detectChanges();
expect(fixture.componentInstance).toBeDefined();
const container = fixture.debugElement.children[0].componentInstance;
expect(container.toasterconfig.tapToDismiss).toBe(true);
fixture.componentInstance.toasterService.pop('success', 'test', 'test');
fixture.detectChanges();
expect(container.toasts.length).toBe(1);
const toast = fixture.nativeElement.querySelector('div.toast');
toast.click();
fixture.detectChanges();
expect(container.toasts.length).toBe(0);
});
it('should invoke the click event when the close button is clicked even if !tapToDismiss', () => {
fixture.detectChanges();
const container = fixture.debugElement.children[0].componentInstance;
expect(container.toasterconfig.tapToDismiss).toBe(false);
fixture.componentInstance.toasterService.pop('success', 'test', 'test');
fixture.detectChanges();
expect(container.toasts.length).toBe(1);
const toastButton = fixture.nativeElement.querySelector('.toast-close-button');
toastButton.click();
fixture.detectChanges();
expect(container.toasts.length).toBe(0);
});
it('should remove toast if clickHandler evaluates to true', () => {
fixture.detectChanges();
const container = fixture.debugElement.children[0].componentInstance;
const toast: Toast = {
type: 'success', clickHandler: () => {
return true;
}
};
fixture.componentInstance.toasterService.pop(toast);
fixture.detectChanges();
expect(container.toasts.length).toBe(1);
const toastButton = fixture.nativeElement.querySelector('.toast-close-button');
toastButton.click();
fixture.detectChanges();
expect(container.toasts.length).toBe(0);
});
it('should not remove toast if clickHandler evaluates to false', () => {
fixture.detectChanges();
const container = fixture.debugElement.children[0].componentInstance;
const toast: Toast = {
type: 'success', clickHandler: () => {
return false;
}
};
fixture.componentInstance.toasterService.pop(toast);
fixture.detectChanges();
expect(container.toasts.length).toBe(1);
const toastButton = fixture.nativeElement.querySelector('.toast-close-button');
toastButton.click();
fixture.detectChanges();
fixture.detectChanges();
expect(container.toasts.length).toBe(1);
});
it('should log error if clickHandler is not a function and not remove toast', () => {
fixture.detectChanges();
const container = fixture.debugElement.children[0].componentInstance;
const clickHandler = <ClickHandler>{};
const toast = { type: 'success', clickHandler: clickHandler };
fixture.componentInstance.toasterService.pop(toast);
fixture.detectChanges();
expect(container.toasts.length).toBe(1);
const toastButton = fixture.nativeElement.querySelector('.toast-close-button');
toastButton.click();
fixture.detectChanges();
expect(container.toasts.length).toBe(1);
});
it('addToast should render component if it exists', () => {
fixture.detectChanges();
const container = fixture.debugElement.children[0].componentInstance;
const toast: Toast = {
type: 'success',
title: 'Yay',
body: TestDynamicComponent,
bodyOutputType: BodyOutputType.Component
};
fixture.componentInstance.toasterService.pop(toast);
fixture.detectChanges();
expect(container.toasts.length).toBe(1);
const renderedToast = fixture.nativeElement.querySelector('test-dynamic-component');
expect(renderedToast.innerHTML).toBe('<div>loaded via component</div>');
});
it('addToast should render module if it exists', () => {
fixture.detectChanges();
const container = fixture.debugElement.children[0].componentInstance;
const toast: Toast = {
type: 'success',
title: 'Yay',
body: TestDynamicComponent,
bodyOutputType: BodyOutputType.Component
};
fixture.componentInstance.toasterService.pop(toast);
fixture.detectChanges();
expect(container.toasts.length).toBe(1);
const renderedToast = fixture.nativeElement.querySelector('test-dynamic-component');
expect(renderedToast.innerHTML).toBe('<div>loaded via component</div>');
});
it('addToast should render html passed in toast.body if bodyOutputType is TrustedHtml', () => {
const textContent = 'here is test text';
const htmlContent = '<h4>' + textContent + '</h4>';
fixture.detectChanges();
const container = fixture.debugElement.children[0].componentInstance;
const toast: Toast = {
type: 'success',
title: 'Yay',
body: htmlContent,
bodyOutputType: BodyOutputType.TrustedHtml
};
fixture.componentInstance.toasterService.pop(toast);
fixture.detectChanges();
expect(container.toasts.length).toBe(1);
const renderedToast = fixture.nativeElement.querySelector('.toast-message');
const innerBody = renderedToast.querySelector('div');
expect(innerBody.innerHTML).toBe(htmlContent);
expect(innerBody.textContent).toBe(textContent);
expect(innerBody.innerHTML).not.toBe(innerBody.textContent);
});
it('addToast will not render html if bodyOutputType is TrustedHtml and body is null', () => {
fixture.detectChanges();
const container = fixture.debugElement.children[0].componentInstance;
const toast: Toast = {
type: 'success',
title: 'Yay',
body: null,
bodyOutputType: BodyOutputType.TrustedHtml
};
fixture.componentInstance.toasterService.pop(toast);
fixture.detectChanges();
expect(container.toasts.length).toBe(1);
const renderedToast = fixture.nativeElement.querySelector('.toast-message');
const innerBody = renderedToast.querySelector('div');
expect(innerBody.innerHTML).toBe('');
});
it('addToast will render encoded text instead of html if bodyOutputType is Default', () => {
const textContent = 'here is test text';
const htmlContent = '<h4>' + textContent + '</h4>';
const encodedString = '<h4>here is test text</h4>';
fixture.detectChanges();
const container = fixture.debugElement.children[0].componentInstance;
const toast: Toast = {
type: 'success',
title: 'Yay',
body: htmlContent,
bodyOutputType: BodyOutputType.Default
};
fixture.componentInstance.toasterService.pop(toast);
fixture.detectChanges();
expect(container.toasts.length).toBe(1);
const renderedToast = fixture.nativeElement.querySelector('.toast-message');
const innerBody = renderedToast.querySelector('div');
expect(innerBody.innerHTML).toBe(encodedString);
expect(innerBody.textContent).toBe(htmlContent);
});
});
describe('Multiple ToasterContainerComponent components', () => {
let fixture: ComponentFixture<TestComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestComponent],
imports: [ToasterModule, TestDynamicComponentModule, BrowserAnimationsModule]
});
TestBed.overrideComponent(TestComponent,
{
set: {
template: `<toaster-container [toasterconfig]="toasterconfig"></toaster-container>
<toaster-container [toasterconfig]="toasterconfig2"></toaster-container>`
}
}
);
fixture = TestBed.createComponent<TestComponent>(TestComponent);
});
it('should create multiple container instances', () => {
fixture.componentInstance.toasterconfig.toastContainerId = 1;
fixture.componentInstance.toasterconfig2.toastContainerId = 2;
fixture.detectChanges();
expect(fixture).toBeDefined();
expect(fixture.componentInstance.toasterconfig).toBeDefined();
expect(fixture.componentInstance.toasterconfig2).toBeDefined();
});
it('should only receive toasts targeted for that container', () => {
fixture.componentInstance.toasterconfig.toastContainerId = 1;
fixture.componentInstance.toasterconfig2.toastContainerId = 2;
fixture.detectChanges();
const toast1: Toast = {
type: 'success',
title: 'fixture 1',
toastContainerId: 1
};
const toast2: Toast = {
type: 'success',
title: 'fixture 2',
toastContainerId: 2
};
fixture.componentInstance.toasterService.pop(toast1);
fixture.componentInstance.toasterService.pop(toast2);
fixture.detectChanges();
const container1 = fixture.debugElement.children[0].componentInstance;
const container2 = fixture.debugElement.children[1].componentInstance;
expect(container1.toasts.length).toBe(1);
expect(container2.toasts.length).toBe(1);
expect(container1.toasts[0].title).toBe('fixture 1');
expect(container2.toasts[0].title).toBe('fixture 2');
});
});
describe('ToasterContainerComponent when included as a component with bindings', () => {
let fixture: ComponentFixture<TestComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestComponent],
imports: [ToasterModule, TestBoundDynamicComponentModule, BrowserAnimationsModule]
});
fixture = TestBed.createComponent<TestComponent>(TestComponent);
});
it('should use the bound toasterconfig object if provided', () => {
fixture.detectChanges();
expect(fixture.componentInstance).toBeDefined();
const container = fixture.debugElement.children[0].componentInstance;
expect(container).toBeDefined();
expect(container.toasterconfig).toBeDefined();
expect(container.toasterconfig.showCloseButton).toBe(true);
expect(container.toasterconfig.tapToDismiss).toBe(false);
expect(container.toasterconfig.timeout).toBe(0);
});
it('should render the dynamic bound content', () => {
fixture.detectChanges();
const container = fixture.debugElement.children[0].componentInstance;
const toast: Toast = {
type: 'success',
title: 'Yay',
body: TestBoundDynamicComponent,
bodyOutputType: BodyOutputType.Component
};
fixture.componentInstance.toasterService.pop(toast);
fixture.detectChanges();
expect(container.toasts.length).toBe(1);
const renderedToast = fixture.nativeElement.querySelector('bound-dynamic-component');
expect(renderedToast.innerHTML).toBe('<div>Some value loaded via component<button id="click"></button></div>');
});
it('should propagate the toast instance to the component', () => {
fixture.detectChanges();
const container = fixture.debugElement.children[0].componentInstance;
const toast: Toast = {
type: 'success',
title: 'test',
body: TestBoundDynamicComponent,
bodyOutputType: BodyOutputType.Component
};
const toastInstance = fixture.componentInstance.toasterService.pop(toast);
fixture.detectChanges();
expect(container.toasts.length).toBe(1);
expect(toastInstance.title).toBe('test');
const clickButton = fixture.nativeElement.querySelector('#click');
clickButton.click();
fixture.detectChanges();
expect(toastInstance.title).toBe('updated title');
});
});