From eebbd0111f9eaff75240b051b4f6e13aa2a0577e Mon Sep 17 00:00:00 2001 From: Stabzs Date: Thu, 1 Sep 2016 21:49:27 -0600 Subject: [PATCH] feat(library): upgrade to RC6 Angular: RC6: The library has been updated to Angular RC6. Closes https://github.com/Stabzs/Angular2-Toaster/issues/52. Documentation: Updated to close https://github.com/Stabzs/Angular2-Toaster/issues/51. package dependencies: @angular packages and the rxjs package have been removed from dependencies and added to peerDependencies to allow for more flexible consumption of alternative builds and configurations. The consumer is now responsible to ensure that the correct version is used per the minimum requirements in https://github.com/Stabzs/Angular2-Toaster/blob/master/package.json. Closes https://github.com/Stabzs/Angular2-Toaster/issues/50. toast.component: Due to Angular2-RC5 deprecating `ComponentResolver` and Angular2-RC6 removing `ComponentResolver`, dynamic component resolution has been moved to `Compiler.compileComponentAsync`. toast.component: Dynamic body rendering via component has been moved to the `ngAfterViewInit` lifecycle hook to ensure full module compilation is complete and metadata is attached before attempting to render the component. toast.component: RC6 requires that all dynamically rendered components be enclosed in a `NgModule`. If a module is not used, an error will be thrown at runtime. --- CHANGELOG.md | 27 ++++ README.md | 6 +- demo/systemjs/package.json | 2 +- karma-test-shim.js | 129 ++++++----------- karma.conf.js | 19 ++- package.json | 26 ++-- src/toast.component.ts | 23 +-- src/toaster-container.component.spec.ts | 185 +++++++++++++++--------- systemjs.config.js | 52 +++++++ 9 files changed, 280 insertions(+), 189 deletions(-) create mode 100644 systemjs.config.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 50a2a328..78b7a4c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,30 @@ +# 0.5.0-rc.6 (2016-09-01) +### Features +* **Angular: RC6:** The library has been updated to Angular RC6. +Closes [#52](https://github.com/Stabzs/Angular2-Toaster/issues/52). +* **Documentation:** Updated to close +[#51](https://github.com/Stabzs/Angular2-Toaster/issues/51). + +### Breaking Changes +* **package dependencies:** @angular packages and the rxjs package have been removed from +dependencies and added to peerDependencies to allow for more flexible consumption of alternative +builds and configurations. The consumer is now responsible to ensure that the correct version is +used per the minimum requirements in +[package.json](https://github.com/Stabzs/Angular2-Toaster/blob/master/package.json). +Closes [#50](https://github.com/Stabzs/Angular2-Toaster/issues/50). + +* **toast.component:** Due to Angular2-RC5 deprecating `ComponentResolver` and Angular2-RC6 +removing `ComponentResolver`, dynamic component resolution has been moved to +`Compiler.compileComponentAsync`. + +* **toast.component:** Dynamic body rendering via component has been moved to the `ngAfterViewInit` +lifecycle hook to ensure full module compilation is complete and metadata is attached before +attempting to render the component. + +* **toast.component:** RC6 requires that all dynamically rendered components be enclosed in a +`NgModule`. If a module is not used, an error will be thrown at runtime. + + # 0.4.0-rc.5 (2016-08-24) ### Features * **toast.module:** toast.module renamed to **toaster.module** for greater consistency with other diff --git a/README.md b/README.md index 2c8c2e8d..bb2909af 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ largely based off of [AngularJS-Toaster](https://github.com/jirikavi/AngularJS-Toaster). [![Build Status](https://travis-ci.org/Stabzs/Angular2-Toaster.svg?branch=master)](https://travis-ci.org/Stabzs/Angular2-Toaster) -[![Coverage Status](https://coveralls.io/repos/github/Stabzs/Angular2-Toaster/badge.svg?branch=master&busted=0.3.6-rc.4)](https://coveralls.io/github/Stabzs/Angular2-Toaster?branch=master) +[![Coverage Status](https://coveralls.io/repos/github/Stabzs/Angular2-Toaster/badge.svg?branch=master&b=0.5.0-rc.6)](https://coveralls.io/github/Stabzs/Angular2-Toaster?branch=master) -### Current Version 0.4.0-rc.5 +### Current Version 0.5.0-rc.6 ## Installation: @@ -56,7 +56,7 @@ A dynamic Angular2 and Typescript demo can be found at ## Getting Started With Default Configuration - NgModule: ```typescript -import {NgModule} from '@angular/core'; +import {NgModule, Component} from '@angular/core'; import {ToasterModule, ToasterService} from 'angular2-toaster/angular2-toaster'; import {Root} from './root.component' diff --git a/demo/systemjs/package.json b/demo/systemjs/package.json index d24cd3c8..778a8a40 100644 --- a/demo/systemjs/package.json +++ b/demo/systemjs/package.json @@ -24,7 +24,7 @@ "@angular/platform-browser": "2.0.0-rc.5", "@angular/platform-browser-dynamic": "2.0.0-rc.5", "rxjs": "5.0.0-beta.6", - "angular2-toaster": "0.4.0-rc.5", + "angular2-toaster": "0.5.0-rc.5", "es6-shim": "0.35.0", "http-server": "^0.8.5", "reflect-metadata": "0.1.3", diff --git a/karma-test-shim.js b/karma-test-shim.js index 10156b2b..63456d18 100644 --- a/karma-test-shim.js +++ b/karma-test-shim.js @@ -1,95 +1,54 @@ -//Based on https://github.com/mgechev/angular2-seed/blob/master/test-main.js -//Updated with excellent insight from https://github.com/antonybudianto/angular2-starter - -// Turn on full stack traces in errors to help debugging +/*global jasmine, __karma__, window*/ Error.stackTraceLimit = Infinity; - jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000; -// Cancel Karma's synchronous start, -// we will call `__karma__.start()` later, once all the specs are loaded. -__karma__.loaded = function () { }; - -var paths = { - 'n:*': 'node_modules/*' -}; - -// map tells the System loader where to look for things -var map = { - 'lib': 'lib', - 'src': 'src', - 'rxjs': 'n:rxjs', - '@angular': 'n:@angular' +__karma__.loaded = function () { }; -var packages = { - 'src': { defaultExtension: 'ts', format: 'register' }, - 'lib': { defaultExtension: 'js' }, - 'rxjs': { defaultExtension: 'js' } -}; - -var packageNames = [ - '@angular/common', - '@angular/compiler', - '@angular/core', - '@angular/platform-browser', - '@angular/platform-browser-dynamic', - '@angular/testing', -]; - -// add package entries for angular packages in the form '@angular/common': { main: 'index.js', defaultExtension: 'js' } -packageNames.forEach(function (pkgName) { - packages[pkgName] = { main: 'index.js', defaultExtension: 'js' }; -}); - -var config = { - baseURL: '/base/', - map: map, - packages: packages, - paths: paths -}; - -System.config(config); - - -Promise.all([ - System.import('@angular/platform-browser/src/browser/browser_adapter'), - System.import('@angular/platform-browser-dynamic/testing'), - System.import('@angular/core/testing'), -]).then(function (modules) { - var browser_adapter = modules[0]; - var providers = modules[1]; - var testing = modules[2]; - testing.setBaseTestProviders(providers.TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS, - providers.TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS); - - browser_adapter.BrowserDomAdapter.makeCurrent(); -}).then(function () { - return Promise.all( - Object.keys(window.__karma__.files) - .filter(onlySpecFiles) - .map(file2moduleName) - .map(importModules) - ); -}) - .then(function () { - __karma__.start(); - }, function (error) { - console.error(error.stack || error); - __karma__.start(); - }); +function isJsFile(path) { + return path.slice(-3) == '.js'; +} -function onlySpecFiles(path) { - return /[\.|-]spec\.js$/.test(path); +function isSpecFile(path) { + return /\.spec\.js$/.test(path); } -// Normalize paths to module names. -function file2moduleName(filePath) { - return filePath.replace(/\\/g, '/') - .replace(/^\/base\//, '') - .replace(/\.js/, ''); +function isBuiltFile(path) { + var builtPath = '/base/lib/'; + return isJsFile(path) && (path.substr(0, builtPath.length) == builtPath); } -function importModules(path) { - return System.import(path); -} \ No newline at end of file +var allSpecFiles = Object.keys(window.__karma__.files) + .filter(isSpecFile) + .filter(isBuiltFile); + +System.config({ + baseURL: '/base', + packageWithIndex: true +}); + +System.import('systemjs.config.js') + .then(() => Promise.all([ + System.import('@angular/core/testing'), + System.import('@angular/platform-browser-dynamic/testing') + ])) + .then((providers) => { + var coreTesting = providers[0]; + var browserTesting = providers[1]; + coreTesting.TestBed.initTestEnvironment( + browserTesting.BrowserDynamicTestingModule, + browserTesting.platformBrowserDynamicTesting()); + + }) + .then(function () { + // Finally, load all spec files. + // This will run the tests directly. + return Promise.all( + allSpecFiles.map(function (moduleName) { + return System.import(moduleName); + })); + }) + .then(__karma__.start, function (error) { + console.error(error.stack || error); + __karma__.start(); + }); \ No newline at end of file diff --git a/karma.conf.js b/karma.conf.js index f7dde41e..e56c1ea6 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,5 +1,5 @@ module.exports = function (config) { - var dependencies = require('./package.json').dependencies; + var dependencies = require('./package.json').peerDependencies; var excludedDependencies = [ 'systemjs', 'zone.js' ]; @@ -10,17 +10,28 @@ module.exports = function (config) { frameworks: ['jasmine'], files: [ + 'node_modules/reflect-metadata/Reflect.js', 'node_modules/zone.js/dist/zone.js', 'node_modules/zone.js/dist/long-stack-trace-zone.js', + 'node_modules/zone.js/dist/proxy.js', + 'node_modules/zone.js/dist/sync-test.js', 'node_modules/zone.js/dist/jasmine-patch.js', + 'node_modules/zone.js/dist/async-test.js', + 'node_modules/zone.js/dist/fake-async-test.js', 'node_modules/es6-promise/dist/es6-promise.js', 'node_modules/es6-shim/es6-shim.js', 'node_modules/systemjs/dist/system-polyfills.js', - 'node_modules/reflect-metadata/Reflect.js', - 'node_modules/zone.js/dist/async-test.js', - 'node_modules/zone.js/dist/fake-async-test.js', 'node_modules/systemjs/dist/system.src.js', + { pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false }, + { pattern: 'node_modules/rxjs/**/*.js.map', included: false, watched: false }, + + // Angular 2 itself and the testing library + {pattern: 'node_modules/@angular/**/*.js', included: false, watched: false}, + {pattern: 'node_modules/@angular/**/*.js.map', included: false, watched: false}, + + {pattern: 'systemjs.config.js', included: false, watched: false}, + 'karma-test-shim.js', { pattern: 'lib/**/*.js', included: false }, diff --git a/package.json b/package.json index 50897fde..0c6dfd88 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "angular2-toaster", - "version": "0.4.0-rc.5", + "version": "0.5.0-rc.6", "description": "An Angular 2 Toaster Notification library based on AngularJS-Toaster", "main": "angular2-toaster.ts", "scripts": { @@ -33,13 +33,13 @@ "url": "https://github.com/stabzs/Angular2-Toaster/issues" }, "typings": "./angular2-toaster.d.ts", - "dependencies": { - "@angular/common": "^2.0.0-rc.5", - "@angular/compiler": "^2.0.0-rc.5", - "@angular/core": "^2.0.0-rc.5", - "@angular/platform-browser": "^2.0.0-rc.5", - "@angular/platform-browser-dynamic": "^2.0.0-rc.5", - "rxjs": "5.0.0-beta.6" + "peerDependencies": { + "@angular/common": "^2.0.0-rc.6", + "@angular/compiler": "^2.0.0-rc.6", + "@angular/core": "^2.0.0-rc.6", + "@angular/platform-browser": "^2.0.0-rc.6", + "@angular/platform-browser-dynamic": "^2.0.0-rc.6", + "rxjs": "5.0.0-beta.11" }, "devDependencies": { "coveralls": "^2.11.9", @@ -47,15 +47,15 @@ "es6-promise": "3.1.2", "es6-shim": "0.35.0", "http-server": "^0.9.0", - "jasmine-core": "2.4.1", - "karma": "^0.13.22", + "jasmine-core": "2.5.0", + "karma": "^1.2.0", "karma-chrome-launcher": "^1.0.1", "karma-coverage": "^0.5.5", - "karma-jasmine": "^0.3.8", + "karma-jasmine": "^1.0.2", "reflect-metadata": "0.1.3", "remap-istanbul": "^0.6.3", "systemjs": "^0.19.27", "typescript": "1.8.10", - "zone.js": "0.6.12" + "zone.js": "0.6.17" } -} \ No newline at end of file +} diff --git a/src/toast.component.ts b/src/toast.component.ts index 5bfdfafb..84f7b71b 100644 --- a/src/toast.component.ts +++ b/src/toast.component.ts @@ -1,6 +1,6 @@ -import {Component, Input, ViewChild, ComponentResolver, ViewContainerRef, EventEmitter} +import {Component, Input, ViewChild, ViewContainerRef, EventEmitter, ComponentFactoryResolver} from '@angular/core'; -import {DomSanitizationService, SafeHtml} from '@angular/platform-browser' +import {DomSanitizer, SafeHtml} from '@angular/platform-browser' import {Toast} from './toast'; import {BodyOutputType} from './bodyOutputType'; @@ -24,7 +24,7 @@ import {BodyOutputType} from './bodyOutputType'; }) export class ToastComponent { - + @Input() toast: Toast; @Input() iconClass: string; @ViewChild('componentBody', { read: ViewContainerRef }) componentBody: ViewContainerRef; @@ -35,22 +35,23 @@ export class ToastComponent { public clickEvent = new EventEmitter(); constructor( - private resolver: ComponentResolver, - private sanitizer: DomSanitizationService + private sanitizer: DomSanitizer, + private componentFactoryResolver : ComponentFactoryResolver ) {} ngOnInit() { - if (this.toast.bodyOutputType === this.bodyOutputType.Component) { - this.resolver.resolveComponent(this.toast.body).then(factory => { - this.componentBody.createComponent(factory, 0, this.componentBody.injector); - }); - } - if (this.toast.closeHtml) { this.safeCloseHtml = this.sanitizer.bypassSecurityTrustHtml(this.toast.closeHtml); } } + ngAfterViewInit() { + if (this.toast.bodyOutputType === this.bodyOutputType.Component) { + let component = this.componentFactoryResolver.resolveComponentFactory(this.toast.body); + this.componentBody.createComponent(component, null, this.componentBody.injector); + } + } + click(event, toast: Toast) { event.stopPropagation(); this.clickEvent.emit({ diff --git a/src/toaster-container.component.spec.ts b/src/toaster-container.component.spec.ts index 099e8cc9..035e46d5 100644 --- a/src/toaster-container.component.spec.ts +++ b/src/toaster-container.component.spec.ts @@ -1,5 +1,5 @@ -import {Component} from '@angular/core'; -import {TestBed} from '@angular/core/testing/test_bed'; +import {Component, NgModule} from '@angular/core'; +import {TestBed} from '@angular/core/testing'; import {ComponentFixture} from '@angular/core/testing/component_fixture'; import {Toast, ClickHandler} from './toast'; @@ -26,12 +26,20 @@ export class TestComponent { public toasterconfig2: ToasterConfig = new ToasterConfig({ showCloseButton: true, tapToDismiss: false, timeout: 0, toastContainerId: 2 }); } + // Mock component for testing bodyOutputType Component rendering @Component({ selector: 'test-dynamic-component', template: `
loaded via component
` }) -class TestDynamicComponent { } +export class TestDynamicComponent { } + +@NgModule({ + imports: [BrowserModule], + bootstrap: [TestDynamicComponent], + declarations: [TestDynamicComponent] +}) +export class TestDynamicModule { } describe('ToasterContainerComponent with sync ToasterService', () => { @@ -41,11 +49,11 @@ describe('ToasterContainerComponent with sync ToasterService', () => { beforeEach(() => { TestBed.configureTestingModule({ - declarations: [TestComponent, TestDynamicComponent], + declarations: [TestComponent], imports: [ToasterModule, BrowserModule] }); - fixture = TestBed.createComponent(TestComponent); + fixture = TestBed.createComponent(TestComponent); toasterContainer = fixture.debugElement.children[0].componentInstance; toasterService = fixture.componentInstance.toasterService; return fixture; @@ -60,37 +68,55 @@ describe('ToasterContainerComponent with sync ToasterService', () => { }); it('should pop toast asynchronously', () => { - toasterContainer.ngOnInit(); - - toasterService.popAsync('success', 'test', 'test') - .subscribe(toast => { - expect(toast).toBeDefined(); - expect(toast.type).toBe('success'); - expect(toasterContainer.toasts.length).toBe(1); - expect(toast.toastId).toBe(toasterContainer.toasts[0].toastId); - }); + // create test-specific fixture to protect against + // container being overwritten by other tests since this + // test now executes fully asynchronously + let fixture = TestBed.createComponent(TestComponent); + let toasterContainer = fixture.debugElement.children[0].componentInstance; + let toasterService = fixture.componentInstance.toasterService; + + fixture.whenStable().then(() => { + toasterContainer.ngOnInit(); + + toasterService.popAsync('success', 'test', 'test') + .subscribe(toast => { + expect(toast).toBeDefined(); + expect(toast.type).toBe('success'); + expect(toasterContainer.toasts.length).toBe(1); + expect(toast.toastId).toBe(toasterContainer.toasts[0].toastId); + }); + }); }); it('should pop toast asynchronously multiple times', () => { - toasterContainer.ngOnInit(); - - toasterService.popAsync('success', 'test', 'test'); - toasterService.popAsync('success', 'test', 'test'); - toasterService.popAsync('success', 'test', 'test') - .subscribe(toast => { - expect(toast).toBeDefined(); - expect(toast.type).toBe('success'); - - var locatedToast; - for (var i = 0; i < toasterContainer.toasts.length; i++) { - if (toasterContainer.toasts[i].toastId === toast.toastId) { - locatedToast = toasterContainer.toasts[i]; - break; + // create test-specific fixture to protect against + // container being overwritten by other tests since this + // test now executes fully asynchronously + let fixture = TestBed.createComponent(TestComponent); + let toasterContainer = fixture.debugElement.children[0].componentInstance; + let toasterService = fixture.componentInstance.toasterService; + + fixture.whenStable().then(() => { + toasterContainer.ngOnInit(); + + toasterService.popAsync('success', 'test', 'test'); + toasterService.popAsync('success', 'test', 'test'); + toasterService.popAsync('success', 'test', 'test') + .subscribe(toast => { + expect(toast).toBeDefined(); + expect(toast.type).toBe('success'); + + var locatedToast; + for (var i = 0; i < toasterContainer.toasts.length; i++) { + if (toasterContainer.toasts[i].toastId === toast.toastId) { + locatedToast = toasterContainer.toasts[i]; + break; + } } - } - expect(locatedToast).toBeDefined(); - }); + expect(locatedToast).toBeDefined(); + }); + }); }); it('should retrieve toast instance from pop observer', () => { @@ -147,14 +173,14 @@ describe('ToasterContainerComponent with sync ToasterService', () => { 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(); }); @@ -375,10 +401,10 @@ describe('ToasterContainerComponent with sync ToasterService', () => { toasterContainer.ngOnInit(); var toast1: Toast = { type: 'info', title: '1', body: '1', showCloseButton: true }; - + toasterService.pop(toast1); fixture.detectChanges(); - + var closeButtonEle = fixture.nativeElement.querySelector('.toast-close-button'); expect(closeButtonEle.innerHTML).toBe(""); }); @@ -391,7 +417,7 @@ describe('ToasterContainerComponent with sync ToasterService', () => { toasterService.pop(toast1); fixture.detectChanges(); - + var closeButtonEle = fixture.nativeElement.querySelector('.toast-close-button'); expect(closeButtonEle.innerHTML).toBe(''); }); @@ -439,36 +465,36 @@ describe('ToasterContainerComponent with sync ToasterService', () => { 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(); - + var toast: Toast = { type: 'success', timeout: 0 }; var poppedToast = toasterService.pop(toast); - - expect(poppedToast.timeoutId).toBeUndefined(); + + 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(); - + var toast: Toast = { type: 'success' }; var poppedToast = toasterService.pop(toast); - - expect(poppedToast.timeoutId).toBeDefined(); - expect(((poppedToast.timeoutId)).data.delay).toBe(1); + + expect(poppedToast.timeoutId).toBeDefined(); + expect(((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(); - + var toast: Toast = { type: 'success' }; var poppedToast = toasterService.pop(toast); - - expect(poppedToast.timeoutId).toBeUndefined(); + + expect(poppedToast.timeoutId).toBeUndefined(); }); it('addToast uses toasterconfig.timeout object if defined and type exists', () => { @@ -585,10 +611,11 @@ describe('ToasterContainerComponent when included as a component', () => { beforeEach(() => { TestBed.configureTestingModule({ - declarations: [TestComponent, TestDynamicComponent], - imports: [ToasterModule] + declarations: [TestComponent], + imports: [ToasterModule, TestDynamicModule] }); - fixture = TestBed.createComponent(TestComponent); + + fixture = TestBed.createComponent(TestComponent); }); it('should use the bound toasterconfig object if provided', () => { @@ -656,10 +683,8 @@ describe('ToasterContainerComponent when included as a component', () => { toastButton.click(); fixture.detectChanges(); - - setTimeout(() => { - expect(container.toasts.length).toBe(0); - }, 0); + + expect(container.toasts.length).toBe(0); }); it('should remove toast if clickHandler evaluates to true', () => { @@ -679,10 +704,8 @@ describe('ToasterContainerComponent when included as a component', () => { toastButton.click(); fixture.detectChanges(); - - setTimeout(() => { - expect(container.toasts.length).toBe(0); - }, 0); + + expect(container.toasts.length).toBe(0); }); it('should not remove toast if clickHandler evaluates to false', () => { @@ -709,7 +732,7 @@ describe('ToasterContainerComponent when included as a component', () => { it('should log error if clickHandler is not a function and not remove toast', () => { fixture.detectChanges(); var container = fixture.debugElement.children[0].componentInstance; - var clickHandler = {}; + var clickHandler = {}; var toast = { type: 'success', clickHandler: clickHandler }; fixture.componentInstance.toasterService.pop(toast); @@ -735,18 +758,36 @@ describe('ToasterContainerComponent when included as a component', () => { fixture.componentInstance.toasterService.pop(toast); fixture.detectChanges(); + expect(container.toasts.length).toBe(1); - setTimeout(() => { - var renderedToast = fixture.nativeElement.querySelector('test-dynamic-component'); - expect(renderedToast.innerHTML).toBe('
loaded via component
'); - }, 1); + var renderedToast = fixture.nativeElement.querySelector('test-dynamic-component'); + expect(renderedToast.innerHTML).toBe('
loaded via component
'); + }); + + + it('addToast should render module if it exists', () => { + fixture.detectChanges(); + var container = fixture.debugElement.children[0].componentInstance; + var toast: Toast = { + type: 'success', + title: 'Yay', + body: TestDynamicComponent, + bodyOutputType: BodyOutputType.Component + }; + + fixture.componentInstance.toasterService.pop(toast); + fixture.detectChanges(); + expect(container.toasts.length).toBe(1); + + var renderedToast = fixture.nativeElement.querySelector('test-dynamic-component'); + expect(renderedToast.innerHTML).toBe('
loaded via component
'); }); - + it('addToast should render html passed in toast.body if bodyOutputType is TrustedHtml', () => { let textContent = 'here is test text'; let htmlContent = '

' + textContent + '

'; - + fixture.detectChanges(); var container = fixture.debugElement.children[0].componentInstance; var toast: Toast = { @@ -766,7 +807,7 @@ describe('ToasterContainerComponent when included as a component', () => { 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(); var container = fixture.debugElement.children[0].componentInstance; @@ -785,12 +826,12 @@ describe('ToasterContainerComponent when included as a component', () => { var innerBody = renderedToast.querySelector('div'); expect(innerBody.innerHTML).toBe(''); }); - + it('addToast will render encoded text instead of html if bodyOutputType is Default', () => { let textContent = 'here is test text'; let htmlContent = '

' + textContent + '

'; const encodedString = '<h4>here is test text</h4>'; - + fixture.detectChanges(); var container = fixture.debugElement.children[0].componentInstance; var toast: Toast = { @@ -817,7 +858,7 @@ describe('Multiple ToasterContainerComponent components', () => { beforeEach(() => { TestBed.configureTestingModule({ declarations: [TestComponent], - imports: [ToasterModule] + imports: [ToasterModule, TestDynamicModule] }); TestBed.overrideComponent(TestComponent, { @@ -828,7 +869,7 @@ describe('Multiple ToasterContainerComponent components', () => { } ); - fixture = TestBed.createComponent(TestComponent); + fixture = TestBed.createComponent(TestComponent); }); it('should create multiple container instances', () => { diff --git a/systemjs.config.js b/systemjs.config.js new file mode 100644 index 00000000..37fa16e5 --- /dev/null +++ b/systemjs.config.js @@ -0,0 +1,52 @@ +/** + * System configuration for Angular 2 samples + * Adjust as necessary for your application needs. + */ +(function (global) { + System.config({ + paths: { + // paths serve as alias + 'npm:': 'node_modules/' + }, + // map tells the System loader where to look for things + map: { + // our app is within the app folder + app: 'src', + + // angular bundles + '@angular/core': 'npm:@angular/core/bundles/core.umd.js', + '@angular/common': 'npm:@angular/common/bundles/common.umd.js', + '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', + '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', + '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', + '@angular/http': 'npm:@angular/http/bundles/http.umd.js', + '@angular/router': 'npm:@angular/router/bundles/router.umd.js', + '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', + + // angular testing umd bundles + '@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js', + '@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js', + '@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js', + '@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js', + '@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js', + '@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js', + '@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js', + '@angular/forms/testing': 'npm:@angular/forms/bundles/forms-testing.umd.js', + + // other libraries + 'rxjs': 'npm:rxjs', + 'angular2-in-memory-web-api': 'npm:angular2-in-memory-web-api', + }, + // packages tells the System loader how to load when no filename and/or no extension + packages: { + rxjs: { + defaultExtension: 'js' + }, + 'angular2-in-memory-web-api': { + defaultExtension: 'js' + }, + src: { defaultExtension: 'ts', format: 'register' }, + lib: { defaultExtension: 'js' }, + } + }); +})(this); \ No newline at end of file