export function main() { describe('WebWorkerPlatformLocation', () => { var uiBus: MessageBus = null; var workerBus: MessageBus = null; var broker: any = null; var TEST_LOCATION = new LocationType( 'http://www.example.com', 'http', 'example.com', 'example.com', '80', '/', '', '', 'http://www.example.com'); function createWebWorkerPlatformLocation(loc: LocationType): WebWorkerPlatformLocation { broker.spy('runOnService').andCallFake((args: UiArguments, returnType: Type) => { if (args.method === 'getLocation') { return PromiseWrapper.resolve(loc); } }); var factory = new MockMessageBrokerFactory(broker); return new WebWorkerPlatformLocation(factory, workerBus, null); } function testPushOrReplaceState(pushState: boolean) { let platformLocation = createWebWorkerPlatformLocation(null); const TITLE = 'foo'; const URL = 'http://www.example.com/foo'; expectBrokerCall(broker, pushState ? 'pushState' : 'replaceState', [null, TITLE, URL]); if (pushState) { platformLocation.pushState(null, TITLE, URL); } else { platformLocation.replaceState(null, TITLE, URL); } } beforeEach(() => { var buses = createPairedMessageBuses(); uiBus = buses.ui; workerBus = buses.worker; workerBus.initChannel('ng-Router'); uiBus.initChannel('ng-Router'); broker = new SpyMessageBroker(); }); it('should throw if getBaseHrefFromDOM is called', () => { let platformLocation = createWebWorkerPlatformLocation(null); expect(() => platformLocation.getBaseHrefFromDOM()).toThrowError(); }); it('should get location on init', () => { let platformLocation = createWebWorkerPlatformLocation(null); expectBrokerCall(broker, 'getLocation'); platformLocation.init(); }); it('should throw if set pathname is called before init finishes', () => { let platformLocation = createWebWorkerPlatformLocation(null); platformLocation.init(); expect(() => platformLocation.pathname = 'TEST').toThrowError(); }); it('should send pathname to render thread', inject([AsyncTestCompleter], (async) => { let platformLocation = createWebWorkerPlatformLocation(TEST_LOCATION); platformLocation.init().then((_) => { let PATHNAME = '/test'; expectBrokerCall(broker, 'setPathname', [PATHNAME]); platformLocation.pathname = PATHNAME; async.done(); }); })); it('should send pushState to render thread', () => { testPushOrReplaceState(true); }); it('should send replaceState to render thread', () => { testPushOrReplaceState(false); }); }); }
export function main() { describe('navigation', () => { var tcb: TestComponentBuilder; var fixture: ComponentFixture; var rtr; beforeEachProviders(() => TEST_ROUTER_PROVIDERS); beforeEach(inject([TestComponentBuilder, Router], (tcBuilder, router) => { tcb = tcBuilder; rtr = router; childCmpInstanceCount = 0; cmpInstanceCount = 0; })); it('should work in a simple case', inject([AsyncTestCompleter], (async) => { compile(tcb) .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([new Route({path: '/test', component: HelloCmp})])) .then((_) => rtr.navigateByUrl('/test')) .then((_) => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText('hello'); async.done(); }); })); it('should navigate between components with different parameters', inject([AsyncTestCompleter], (async) => { compile(tcb) .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([new Route({path: '/user/:name', component: UserCmp})])) .then((_) => rtr.navigateByUrl('/user/brian')) .then((_) => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText('hello brian'); }) .then((_) => rtr.navigateByUrl('/user/igor')) .then((_) => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText('hello igor'); async.done(); }); })); it('should navigate to child routes', inject([AsyncTestCompleter], (async) => { compile(tcb, 'outer { <router-outlet></router-outlet> }') .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([new Route({path: '/a/...', component: ParentCmp})])) .then((_) => rtr.navigateByUrl('/a/b')) .then((_) => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText('outer { inner { hello } }'); async.done(); }); })); it('should navigate to child routes that capture an empty path', inject([AsyncTestCompleter], (async) => { compile(tcb, 'outer { <router-outlet></router-outlet> }') .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([new Route({path: '/a/...', component: ParentCmp})])) .then((_) => rtr.navigateByUrl('/a')) .then((_) => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText('outer { inner { hello } }'); async.done(); }); })); it('should navigate to child routes when the root component has an empty path', inject([AsyncTestCompleter, Location], (async, location) => { compile(tcb, 'outer { <router-outlet></router-outlet> }') .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([new Route({path: '/...', component: ParentCmp})])) .then((_) => rtr.navigateByUrl('/b')) .then((_) => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText('outer { inner { hello } }'); expect(location.urlChanges).toEqual(['/b']); async.done(); }); })); it('should navigate to child routes of async routes', inject([AsyncTestCompleter], (async) => { compile(tcb, 'outer { <router-outlet></router-outlet> }') .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([new AsyncRoute({path: '/a/...', loader: parentLoader})])) .then((_) => rtr.navigateByUrl('/a/b')) .then((_) => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText('outer { inner { hello } }'); async.done(); }); })); it('should reuse common parent components', inject([AsyncTestCompleter], (async) => { compile(tcb) .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([new Route({path: '/team/:id/...', component: TeamCmp})])) .then((_) => rtr.navigateByUrl('/team/angular/user/rado')) .then((_) => { fixture.detectChanges(); expect(cmpInstanceCount).toBe(1); expect(fixture.debugElement.nativeElement).toHaveText('team angular { hello rado }'); }) .then((_) => rtr.navigateByUrl('/team/angular/user/victor')) .then((_) => { fixture.detectChanges(); expect(cmpInstanceCount).toBe(1); expect(fixture.debugElement.nativeElement) .toHaveText('team angular { hello victor }'); async.done(); }); })); it('should not reuse children when parent components change', inject([AsyncTestCompleter], (async) => { compile(tcb) .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([new Route({path: '/team/:id/...', component: TeamCmp})])) .then((_) => rtr.navigateByUrl('/team/angular/user/rado')) .then((_) => { fixture.detectChanges(); expect(cmpInstanceCount).toBe(1); expect(childCmpInstanceCount).toBe(1); expect(fixture.debugElement.nativeElement).toHaveText('team angular { hello rado }'); }) .then((_) => rtr.navigateByUrl('/team/dart/user/rado')) .then((_) => { fixture.detectChanges(); expect(cmpInstanceCount).toBe(2); expect(childCmpInstanceCount).toBe(2); expect(fixture.debugElement.nativeElement).toHaveText('team dart { hello rado }'); async.done(); }); })); it('should inject route data into component', inject([AsyncTestCompleter], (async) => { compile(tcb) .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([ new Route({path: '/route-data', component: RouteDataCmp, data: {isAdmin: true}}) ])) .then((_) => rtr.navigateByUrl('/route-data')) .then((_) => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText('true'); async.done(); }); })); it('should inject route data into component with AsyncRoute', inject([AsyncTestCompleter], (async) => { compile(tcb) .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([ new AsyncRoute( {path: '/route-data', loader: asyncRouteDataCmp, data: {isAdmin: true}}) ])) .then((_) => rtr.navigateByUrl('/route-data')) .then((_) => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText('true'); async.done(); }); })); it('should inject empty object if the route has no data property', inject([AsyncTestCompleter], (async) => { compile(tcb) .then((rtc) => {fixture = rtc}) .then((_) => rtr.config( [new Route({path: '/route-data-default', component: RouteDataCmp})])) .then((_) => rtr.navigateByUrl('/route-data-default')) .then((_) => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText(''); async.done(); }); })); }); }
describe('ChangeDetectorCompiler', () => { beforeEachBindings(() => TEST_PROVIDERS); var parser: TemplateParser; var compiler: ChangeDetectionCompiler; beforeEach(inject([TemplateParser, ChangeDetectionCompiler], (_parser, _compiler) => { parser = _parser; compiler = _compiler; })); describe('compileComponentRuntime', () => { function detectChanges(compiler: ChangeDetectionCompiler, template: string, directives: CompileDirectiveMetadata[] = CONST_EXPR([])): string[] { var type = new CompileTypeMetadata({name: stringify(SomeComponent), moduleUrl: THIS_MODULE_URL}); var parsedTemplate = parser.parse(template, directives, 'TestComp'); var factories = compiler.compileComponentRuntime(type, ChangeDetectionStrategy.Default, parsedTemplate); return testChangeDetector(factories[0]); } describe('no jit', () => { beforeEachBindings(() => [ provide(ChangeDetectorGenConfig, {useValue: new ChangeDetectorGenConfig(true, true, false, false)}) ]); it('should watch element properties', () => { expect(detectChanges(compiler, '<div [el-prop]="someProp">')) .toEqual(['elementProperty(elProp)=someValue']); }); }); describe('jit', () => { beforeEachBindings(() => [ provide(ChangeDetectorGenConfig, {useValue: new ChangeDetectorGenConfig(true, true, false, true)}) ]); it('should watch element properties', () => { expect(detectChanges(compiler, '<div [el-prop]="someProp">')) .toEqual(['elementProperty(elProp)=someValue']); }); }); }); describe('compileComponentCodeGen', () => { function detectChanges(compiler: ChangeDetectionCompiler, template: string, directives: CompileDirectiveMetadata[] = CONST_EXPR([])): Promise<string[]> { var type = new CompileTypeMetadata({name: stringify(SomeComponent), moduleUrl: THIS_MODULE_URL}); var parsedTemplate = parser.parse(template, directives, 'TestComp'); var sourceExpressions = compiler.compileComponentCodeGen(type, ChangeDetectionStrategy.Default, parsedTemplate); var testableModule = createTestableModule(sourceExpressions, 0).getSourceWithImports(); return evalModule(testableModule.source, testableModule.imports, null); } it('should watch element properties', inject([AsyncTestCompleter], (async) => { detectChanges(compiler, '<div [el-prop]="someProp">') .then((value) => { expect(value).toEqual(['elementProperty(elProp)=someValue']); async.done(); }); })); }); });
describe("NgZone", () => { function createZone(enableLongStackTrace) { var zone = new NgZone({enableLongStackTrace: enableLongStackTrace}); zone.overrideOnTurnStart(_log.fn('onTurnStart')); zone.overrideOnTurnDone(_log.fn('onTurnDone')); return zone; } beforeEach(() => { _log = new Log(); _errors = []; _traces = []; }); describe('long stack trace', () => { beforeEach(() => { _zone = createZone(true); }); commonTests(); it('should produce long stack traces', inject([AsyncTestCompleter], (async) => { macroTask(() => { _zone.overrideOnErrorHandler(logError); var c: PromiseCompleter<any> = PromiseWrapper.completer(); _zone.run(() => { TimerWrapper.setTimeout(() => { TimerWrapper.setTimeout(() => { c.resolve(null); throw new BaseException('ccc'); }, 0); }, 0); }); c.promise.then((_) => { expect(_traces.length).toBe(1); expect(_traces[0].length).toBeGreaterThan(1); async.done(); }); }); }), testTimeout); it('should produce long stack traces (when using microtasks)', inject([AsyncTestCompleter], (async) => { macroTask(() => { _zone.overrideOnErrorHandler(logError); var c: PromiseCompleter<any> = PromiseWrapper.completer(); _zone.run(() => { microTask(() => { microTask(() => { c.resolve(null); throw new BaseException("ddd"); }); }); }); c.promise.then((_) => { expect(_traces.length).toBe(1); expect(_traces[0].length).toBeGreaterThan(1); async.done(); }); }); }), testTimeout); }); describe('short stack trace', () => { beforeEach(() => { _zone = createZone(false); }); commonTests(); it('should disable long stack traces', inject([AsyncTestCompleter], (async) => { macroTask(() => { _zone.overrideOnErrorHandler(logError); var c: PromiseCompleter<any> = PromiseWrapper.completer(); _zone.run(() => { TimerWrapper.setTimeout(() => { TimerWrapper.setTimeout(() => { c.resolve(null); throw new BaseException('ccc'); }, 0); }, 0); }); c.promise.then((_) => { expect(_traces.length).toBe(1); expect(_traces[0].length).toEqual(1); async.done(); }); }); }), testTimeout); }); });
export function main() { describe('ContactComponent', () => { let contactService: ContactService; beforeEach(() => { contactService = new ContactService(null); spyOn(contactService, 'find').and.callFake(() => Observable.of(contacts)); spyOn(contactService, 'findOneById').and.callFake((id: string) => Observable.of(contacts.find(it => it._id === id)) ); spyOn(contactService, 'removeOneById').and.callFake((id: string) => { let pos: number; for (let i = 0; i < contacts.length; ++i) { if (contacts[i]._id === id) { pos = i; break; } } return Observable.of(contacts.splice(pos, 1)); }); }); it('should work', inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { tcb.overrideProviders(ContactComponent, [provide(ContactService, { useValue: contactService })]) .createAsync(ContactComponent).then((fixture) => { fixture.detectChanges(); const cmp: ContactComponent = fixture.componentInstance; const compiled = fixture.debugElement.nativeElement; expect(compiled.querySelector('h2').textContent).toEqual('Contacts!'); const itemsSelector = 'tbody tr'; function obtainContactsLenght() { return compiled.querySelectorAll(itemsSelector).length; } const originalLength = obtainContactsLenght(); let newLength = originalLength; expect(originalLength).toBeGreaterThan(0); expect(originalLength).toBe(contacts.length); const existingContact = ObjectUtil.clone(contacts[0]); cmp.select(existingContact._id); fixture.detectChanges(); const selectedContact = cmp.selectedContact; expect(selectedContact._id).toBe(existingContact._id); expect(selectedContact.name).toBe(existingContact.name); cmp.remove(new Event('mock'), existingContact); fixture.detectChanges(); newLength--; expect(obtainContactsLenght()).toBe(newLength); async.done(); }); })); }); }
describe('String', () => { var s; describe('slice', () => { beforeEach(() => { s = 'abcdefghij'; }); it('should return the whole string if neither start nor end are specified', () => { expect(StringWrapper.slice(s)).toEqual('abcdefghij'); }); it('should return up to the end if end is not specified', () => { expect(StringWrapper.slice(s, 1)).toEqual('bcdefghij'); }); it('should support negative start', () => { expect(StringWrapper.slice(s, -1)).toEqual('j'); }); it('should support negative end', () => { expect(StringWrapper.slice(s, -3, -1)).toEqual('hi'); }); it('should return empty string if start is greater than end', () => { expect(StringWrapper.slice(s, 4, 2)).toEqual(''); expect(StringWrapper.slice(s, -2, -4)).toEqual(''); }); }); describe('stripLeft', () => { it('should strip the first character of the string if it matches the provided input', () => { var input = '~angular2 is amazing'; var expectedOutput = 'angular2 is amazing'; expect(StringWrapper.stripLeft(input, '~')).toEqual(expectedOutput); }); it('should keep stripping characters from the start until the first unmatched character', () => { var input = '#####hello'; var expectedOutput = 'hello'; expect(StringWrapper.stripLeft(input, '#')).toEqual(expectedOutput); }); it('should not alter the provided input if the first character does not match the provided input', () => { var input = '+angular2 is amazing'; expect(StringWrapper.stripLeft(input, '*')).toEqual(input); }); it('should not do any alterations when an empty string or null value is passed in', () => { expect(StringWrapper.stripLeft('', 'S')).toEqual(''); expect(StringWrapper.stripLeft(null, 'S')).toEqual(null); }); }); describe('stripRight', () => { it('should strip the first character of the string if it matches the provided input', () => { var input = 'angular2 is amazing!'; var expectedOutput = 'angular2 is amazing'; expect(StringWrapper.stripRight(input, '!')).toEqual(expectedOutput); }); it('should not alter the provided input if the first character does not match the provided input', () => { var input = 'angular2 is amazing+'; expect(StringWrapper.stripRight(input, '*')).toEqual(input); }); it('should keep stripping characters from the end until the first unmatched character', () => { var input = 'hi&!&&&&&'; var expectedOutput = 'hi&!'; expect(StringWrapper.stripRight(input, '&')).toEqual(expectedOutput); }); it('should not do any alterations when an empty string or null value is passed in', () => { expect(StringWrapper.stripRight('', 'S')).toEqual(''); expect(StringWrapper.stripRight(null, 'S')).toEqual(null); }); }); describe('resolveEnumToken', () => { it('should resolve a token given an enum and index values', () => { var token = UsefulEnum.MyToken; expect(resolveEnumToken(UsefulEnum, token)).toEqual('MyToken'); token = UsefulEnum.MyOtherToken; expect(resolveEnumToken(UsefulEnum, token)).toEqual('MyOtherToken'); }); }); describe('hasConstructor', () => { it('should be true when the type matches', () => { expect(hasConstructor(new MySuperclass(), MySuperclass)).toEqual(true); }); it('should be false for subtypes', () => { expect(hasConstructor(new MySubclass(), MySuperclass)).toEqual(false); }); }); });
export function main() { describe('Router lifecycle hooks', () => { var tcb: TestComponentBuilder; var fixture: ComponentFixture; var rtr: Router; beforeEachProviders(() => TEST_ROUTER_PROVIDERS); beforeEach(inject( [TestComponentBuilder, Router], (tcBuilder: TestComponentBuilder, router: Router) => { tcb = tcBuilder; rtr = router; cmpInstanceCount = 0; log = []; eventBus = new EventEmitter(); })); it('should call the routerOnActivate hook', inject([AsyncTestCompleter], (async) => { compile(tcb) .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([new Route({path: '/...', component: LifecycleCmp})])) .then((_) => rtr.navigateByUrl('/on-activate')) .then((_) => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText('activate cmp'); expect(log).toEqual(['activate: null -> /on-activate']); async.done(); }); })); it('should wait for a parent component\'s routerOnActivate hook to resolve before calling its child\'s', inject([AsyncTestCompleter], (async) => { compile(tcb) .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([new Route({path: '/...', component: LifecycleCmp})])) .then((_) => { ObservableWrapper.subscribe<string>(eventBus, (ev) => { if (ev.startsWith('parent activate')) { completer.resolve(true); } }); rtr.navigateByUrl('/parent-activate/child-activate').then((_) => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText('parent {activate cmp}'); expect(log).toEqual([ 'parent activate: null -> /parent-activate', 'activate: null -> /child-activate' ]); async.done(); }); }); })); it('should call the routerOnDeactivate hook', inject([AsyncTestCompleter], (async) => { compile(tcb) .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([new Route({path: '/...', component: LifecycleCmp})])) .then((_) => rtr.navigateByUrl('/on-deactivate')) .then((_) => rtr.navigateByUrl('/a')) .then((_) => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText('A'); expect(log).toEqual(['deactivate: /on-deactivate -> /a']); async.done(); }); })); it('should wait for a child component\'s routerOnDeactivate hook to resolve before calling its parent\'s', inject([AsyncTestCompleter], (async) => { compile(tcb) .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([new Route({path: '/...', component: LifecycleCmp})])) .then((_) => rtr.navigateByUrl('/parent-deactivate/child-deactivate')) .then((_) => { ObservableWrapper.subscribe<string>(eventBus, (ev) => { if (ev.startsWith('deactivate')) { completer.resolve(true); fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText('parent {deactivate cmp}'); } }); rtr.navigateByUrl('/a').then((_) => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText('A'); expect(log).toEqual([ 'deactivate: /child-deactivate -> null', 'parent deactivate: /parent-deactivate -> /a' ]); async.done(); }); }); })); it('should reuse a component when the routerCanReuse hook returns true', inject([AsyncTestCompleter], (async) => { compile(tcb) .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([new Route({path: '/...', component: LifecycleCmp})])) .then((_) => rtr.navigateByUrl('/on-reuse/1/a')) .then((_) => { fixture.detectChanges(); expect(log).toEqual([]); expect(fixture.debugElement.nativeElement).toHaveText('reuse {A}'); expect(cmpInstanceCount).toBe(1); }) .then((_) => rtr.navigateByUrl('/on-reuse/2/b')) .then((_) => { fixture.detectChanges(); expect(log).toEqual(['reuse: /on-reuse/1 -> /on-reuse/2']); expect(fixture.debugElement.nativeElement).toHaveText('reuse {B}'); expect(cmpInstanceCount).toBe(1); async.done(); }); })); it('should not reuse a component when the routerCanReuse hook returns false', inject([AsyncTestCompleter], (async) => { compile(tcb) .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([new Route({path: '/...', component: LifecycleCmp})])) .then((_) => rtr.navigateByUrl('/never-reuse/1/a')) .then((_) => { fixture.detectChanges(); expect(log).toEqual([]); expect(fixture.debugElement.nativeElement).toHaveText('reuse {A}'); expect(cmpInstanceCount).toBe(1); }) .then((_) => rtr.navigateByUrl('/never-reuse/2/b')) .then((_) => { fixture.detectChanges(); expect(log).toEqual([]); expect(fixture.debugElement.nativeElement).toHaveText('reuse {B}'); expect(cmpInstanceCount).toBe(2); async.done(); }); })); it('should navigate when routerCanActivate returns true', inject([AsyncTestCompleter], (async) => { compile(tcb) .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([new Route({path: '/...', component: LifecycleCmp})])) .then((_) => { ObservableWrapper.subscribe<string>(eventBus, (ev) => { if (ev.startsWith('routerCanActivate')) { completer.resolve(true); } }); rtr.navigateByUrl('/can-activate/a').then((_) => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText('routerCanActivate {A}'); expect(log).toEqual(['routerCanActivate: null -> /can-activate']); async.done(); }); }); })); it('should not navigate when routerCanActivate returns false', inject([AsyncTestCompleter], (async) => { compile(tcb) .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([new Route({path: '/...', component: LifecycleCmp})])) .then((_) => { ObservableWrapper.subscribe<string>(eventBus, (ev) => { if (ev.startsWith('routerCanActivate')) { completer.resolve(false); } }); rtr.navigateByUrl('/can-activate/a').then((_) => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText(''); expect(log).toEqual(['routerCanActivate: null -> /can-activate']); async.done(); }); }); })); it('should navigate away when routerCanDeactivate returns true', inject([AsyncTestCompleter], (async) => { compile(tcb) .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([new Route({path: '/...', component: LifecycleCmp})])) .then((_) => rtr.navigateByUrl('/can-deactivate/a')) .then((_) => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText('routerCanDeactivate {A}'); expect(log).toEqual([]); ObservableWrapper.subscribe<string>(eventBus, (ev) => { if (ev.startsWith('routerCanDeactivate')) { completer.resolve(true); } }); rtr.navigateByUrl('/a').then((_) => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText('A'); expect(log).toEqual(['routerCanDeactivate: /can-deactivate -> /a']); async.done(); }); }); })); it('should not navigate away when routerCanDeactivate returns false', inject([AsyncTestCompleter], (async) => { compile(tcb) .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([new Route({path: '/...', component: LifecycleCmp})])) .then((_) => rtr.navigateByUrl('/can-deactivate/a')) .then((_) => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText('routerCanDeactivate {A}'); expect(log).toEqual([]); ObservableWrapper.subscribe<string>(eventBus, (ev) => { if (ev.startsWith('routerCanDeactivate')) { completer.resolve(false); } }); rtr.navigateByUrl('/a').then((_) => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText('routerCanDeactivate {A}'); expect(log).toEqual(['routerCanDeactivate: /can-deactivate -> /a']); async.done(); }); }); })); it('should run activation and deactivation hooks in the correct order', inject([AsyncTestCompleter], (async) => { compile(tcb) .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([new Route({path: '/...', component: LifecycleCmp})])) .then((_) => rtr.navigateByUrl('/activation-hooks/child')) .then((_) => { expect(log).toEqual([ 'routerCanActivate child: null -> /child', 'routerCanActivate parent: null -> /activation-hooks', 'routerOnActivate parent: null -> /activation-hooks', 'routerOnActivate child: null -> /child' ]); log = []; return rtr.navigateByUrl('/a'); }) .then((_) => { expect(log).toEqual([ 'routerCanDeactivate parent: /activation-hooks -> /a', 'routerCanDeactivate child: /child -> null', 'routerOnDeactivate child: /child -> null', 'routerOnDeactivate parent: /activation-hooks -> /a' ]); async.done(); }); })); it('should only run reuse hooks when reusing', inject([AsyncTestCompleter], (async) => { compile(tcb) .then((rtc) => {fixture = rtc}) .then((_) => rtr.config([new Route({path: '/...', component: LifecycleCmp})])) .then((_) => rtr.navigateByUrl('/reuse-hooks/1')) .then((_) => { expect(log).toEqual([ 'routerCanActivate: null -> /reuse-hooks/1', 'routerOnActivate: null -> /reuse-hooks/1' ]); ObservableWrapper.subscribe<string>(eventBus, (ev) => { if (ev.startsWith('routerCanReuse')) { completer.resolve(true); } }); log = []; return rtr.navigateByUrl('/reuse-hooks/2'); }) .then((_) => { expect(log).toEqual([ 'routerCanReuse: /reuse-hooks/1 -> /reuse-hooks/2', 'routerOnReuse: /reuse-hooks/1 -> /reuse-hooks/2' ]); async.done(); }); })); it('should not run reuse hooks when not reusing', inject([AsyncTestCompleter], (async) => { compile(tcb) .then((_) => rtr.config([new Route({path: '/...', component: LifecycleCmp})])) .then((_) => rtr.navigateByUrl('/reuse-hooks/1')) .then((_) => { expect(log).toEqual([ 'routerCanActivate: null -> /reuse-hooks/1', 'routerOnActivate: null -> /reuse-hooks/1' ]); ObservableWrapper.subscribe<string>(eventBus, (ev) => { if (ev.startsWith('routerCanReuse')) { completer.resolve(false); } }); log = []; return rtr.navigateByUrl('/reuse-hooks/2'); }) .then((_) => { expect(log).toEqual([ 'routerCanReuse: /reuse-hooks/1 -> /reuse-hooks/2', 'routerCanActivate: /reuse-hooks/1 -> /reuse-hooks/2', 'routerCanDeactivate: /reuse-hooks/1 -> /reuse-hooks/2', 'routerOnDeactivate: /reuse-hooks/1 -> /reuse-hooks/2', 'routerOnActivate: /reuse-hooks/1 -> /reuse-hooks/2' ]); async.done(); }); })); }); }
export function main() { describe('Location', () => { var locationStrategy, location; function makeLocation(baseHref: string = '/my/app', provider: any = CONST_EXPR([])): Location { locationStrategy = new MockLocationStrategy(); locationStrategy.internalBaseHref = baseHref; let injector = Injector.resolveAndCreate( [Location, provide(LocationStrategy, {useValue: locationStrategy}), provider]); return location = injector.get(Location); } beforeEach(makeLocation); it('should not prepend urls with starting slash when an empty URL is provided', () => { expect(location.prepareExternalUrl('')).toEqual(locationStrategy.getBaseHref()); }); it('should not prepend path with an extra slash when a baseHref has a trailing slash', () => { let location = makeLocation('/my/slashed/app/'); expect(location.prepareExternalUrl('/page')).toEqual('/my/slashed/app/page'); }); it('should not append urls with leading slash on navigate', () => { location.go('/my/app/user/btford'); expect(locationStrategy.path()).toEqual('/my/app/user/btford'); }); it('should normalize urls on popstate', inject([AsyncTestCompleter], (async) => { locationStrategy.simulatePopState('/my/app/user/btford'); location.subscribe((ev) => { expect(ev['url']).toEqual('/user/btford'); async.done(); }) })); it('should revert to the previous path when a back() operation is executed', () => { var locationStrategy = new MockLocationStrategy(); var location = new Location(locationStrategy); function assertUrl(path) { expect(location.path()).toEqual(path); } location.go('/ready'); assertUrl('/ready'); location.go('/ready/set'); assertUrl('/ready/set'); location.go('/ready/set/go'); assertUrl('/ready/set/go'); location.back(); assertUrl('/ready/set'); location.back(); assertUrl('/ready'); }); it('should incorporate the provided query values into the location change', () => { var locationStrategy = new MockLocationStrategy(); var location = new Location(locationStrategy); location.go('/home', "key=value"); expect(location.path()).toEqual("/home?key=value"); }); }); }
describe('chrome driver extension', () => { var CHROME44_USER_AGENT = '"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.0 Safari/537.36"'; var CHROME45_USER_AGENT = '"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2499.0 Safari/537.36"'; var log; var extension; var blinkEvents = new TraceEventFactory('blink.console', 'pid0'); var v8Events = new TraceEventFactory('v8', 'pid0'); var v8EventsOtherProcess = new TraceEventFactory('v8', 'pid1'); var chromeTimelineEvents = new TraceEventFactory('disabled-by-default-devtools.timeline', 'pid0'); var chrome45TimelineEvents = new TraceEventFactory('devtools.timeline', 'pid0'); var chromeTimelineV8Events = new TraceEventFactory('devtools.timeline,v8', 'pid0'); var chromeBlinkTimelineEvents = new TraceEventFactory('blink,devtools.timeline', 'pid0'); var chromeBlinkUserTimingEvents = new TraceEventFactory('blink.user_timing', 'pid0'); var benchmarkEvents = new TraceEventFactory('benchmark', 'pid0'); var normEvents = new TraceEventFactory('timeline', 'pid0'); function createExtension(perfRecords = null, userAgent = null, messageMethod = 'Tracing.dataCollected') { if (isBlank(perfRecords)) { perfRecords = []; } if (isBlank(userAgent)) { userAgent = CHROME44_USER_AGENT; } log = []; extension = Injector.resolveAndCreate([ ChromeDriverExtension.BINDINGS, bind(WebDriverAdapter) .toValue(new MockDriverAdapter(log, perfRecords, messageMethod)), bind(Options.USER_AGENT).toValue(userAgent) ]) .get(ChromeDriverExtension); return extension; } it('should force gc via window.gc()', inject([AsyncTestCompleter], (async) => { createExtension().gc().then((_) => { expect(log).toEqual([['executeScript', 'window.gc()']]); async.done(); }); })); it('should mark the timeline via console.time()', inject([AsyncTestCompleter], (async) => { createExtension() .timeBegin('someName') .then((_) => { expect(log).toEqual([['executeScript', `console.time('someName');`]]); async.done(); }); })); it('should mark the timeline via console.timeEnd()', inject([AsyncTestCompleter], (async) => { createExtension() .timeEnd('someName') .then((_) => { expect(log).toEqual([['executeScript', `console.timeEnd('someName');`]]); async.done(); }); })); it('should mark the timeline via console.time() and console.timeEnd()', inject([AsyncTestCompleter], (async) => { createExtension() .timeEnd('name1', 'name2') .then((_) => { expect(log) .toEqual([['executeScript', `console.timeEnd('name1');console.time('name2');`]]); async.done(); }); })); describe('readPerfLog Chrome44', () => { it('should normalize times to ms and forward ph and pid event properties', inject([AsyncTestCompleter], (async) => { createExtension([chromeTimelineEvents.complete('FunctionCall', 1100, 5500, null)]) .readPerfLog() .then((events) => { expect(events).toEqual([ normEvents.complete('script', 1.1, 5.5, null), ]); async.done(); }); })); it('should normalize "tdur" to "dur"', inject([AsyncTestCompleter], (async) => { var event = chromeTimelineEvents.create('X', 'FunctionCall', 1100, null); event['tdur'] = 5500; createExtension([event]).readPerfLog().then((events) => { expect(events).toEqual([ normEvents.complete('script', 1.1, 5.5, null), ]); async.done(); }); })); it('should report FunctionCall events as "script"', inject([AsyncTestCompleter], (async) => { createExtension([chromeTimelineEvents.start('FunctionCall', 0)]) .readPerfLog() .then((events) => { expect(events).toEqual([ normEvents.start('script', 0), ]); async.done(); }); })); it('should report gc', inject([AsyncTestCompleter], (async) => { createExtension([ chromeTimelineEvents.start('GCEvent', 1000, {'usedHeapSizeBefore': 1000}), chromeTimelineEvents.end('GCEvent', 2000, {'usedHeapSizeAfter': 0}), ]) .readPerfLog() .then((events) => { expect(events).toEqual([ normEvents.start('gc', 1.0, {'usedHeapSize': 1000}), normEvents.end('gc', 2.0, {'usedHeapSize': 0, 'majorGc': false}), ]); async.done(); }); })); it('should ignore major gc from different processes', inject([AsyncTestCompleter], (async) => { createExtension([ chromeTimelineEvents.start('GCEvent', 1000, {'usedHeapSizeBefore': 1000}), v8EventsOtherProcess.start('majorGC', 1100, null), v8EventsOtherProcess.end('majorGC', 1200, null), chromeTimelineEvents.end('GCEvent', 2000, {'usedHeapSizeAfter': 0}), ]) .readPerfLog() .then((events) => { expect(events).toEqual([ normEvents.start('gc', 1.0, {'usedHeapSize': 1000}), normEvents.end('gc', 2.0, {'usedHeapSize': 0, 'majorGc': false}), ]); async.done(); }); })); it('should report major gc', inject([AsyncTestCompleter], (async) => { createExtension([ chromeTimelineEvents.start('GCEvent', 1000, {'usedHeapSizeBefore': 1000}), v8Events.start('majorGC', 1100, null), v8Events.end('majorGC', 1200, null), chromeTimelineEvents.end('GCEvent', 2000, {'usedHeapSizeAfter': 0}), ]) .readPerfLog() .then((events) => { expect(events).toEqual([ normEvents.start('gc', 1.0, {'usedHeapSize': 1000}), normEvents.end('gc', 2.0, {'usedHeapSize': 0, 'majorGc': true}), ]); async.done(); }); })); ['RecalculateStyles', 'Layout', 'UpdateLayerTree', 'Paint'].forEach((recordType) => { it(`should report ${recordType} as "render"`, inject([AsyncTestCompleter], (async) => { createExtension([ chromeTimelineEvents.start(recordType, 1234), chromeTimelineEvents.end(recordType, 2345) ]) .readPerfLog() .then((events) => { expect(events).toEqual([ normEvents.start('render', 1.234), normEvents.end('render', 2.345), ]); async.done(); }); })); }); it('should ignore FunctionCalls from webdriver', inject([AsyncTestCompleter], (async) => { createExtension([ chromeTimelineEvents.start('FunctionCall', 0, {'data': {'scriptName': 'InjectedScript'}}) ]) .readPerfLog() .then((events) => { expect(events).toEqual([]); async.done(); }); })); }); describe('readPerfLog Chrome45', () => { it('should normalize times to ms and forward ph and pid event properties', inject([AsyncTestCompleter], (async) => { createExtension([chromeTimelineV8Events.complete('FunctionCall', 1100, 5500, null)], CHROME45_USER_AGENT) .readPerfLog() .then((events) => { expect(events).toEqual([ normEvents.complete('script', 1.1, 5.5, null), ]); async.done(); }); })); it('should normalize "tdur" to "dur"', inject([AsyncTestCompleter], (async) => { var event = chromeTimelineV8Events.create('X', 'FunctionCall', 1100, null); event['tdur'] = 5500; createExtension([event], CHROME45_USER_AGENT) .readPerfLog() .then((events) => { expect(events).toEqual([ normEvents.complete('script', 1.1, 5.5, null), ]); async.done(); }); })); it('should report FunctionCall events as "script"', inject([AsyncTestCompleter], (async) => { createExtension([chromeTimelineV8Events.start('FunctionCall', 0)], CHROME45_USER_AGENT) .readPerfLog() .then((events) => { expect(events).toEqual([ normEvents.start('script', 0), ]); async.done(); }); })); it('should report minor gc', inject([AsyncTestCompleter], (async) => { createExtension( [ chromeTimelineV8Events.start('MinorGC', 1000, {'usedHeapSizeBefore': 1000}), chromeTimelineV8Events.end('MinorGC', 2000, {'usedHeapSizeAfter': 0}), ], CHROME45_USER_AGENT) .readPerfLog() .then((events) => { expect(events.length).toEqual(2); expect(events[0]).toEqual( normEvents.start('gc', 1.0, {'usedHeapSize': 1000, 'majorGc': false})); expect(events[1]) .toEqual(normEvents.end('gc', 2.0, {'usedHeapSize': 0, 'majorGc': false})); async.done(); }); })); it('should report major gc', inject([AsyncTestCompleter], (async) => { createExtension( [ chromeTimelineV8Events.start('MajorGC', 1000, {'usedHeapSizeBefore': 1000}), chromeTimelineV8Events.end('MajorGC', 2000, {'usedHeapSizeAfter': 0}), ], CHROME45_USER_AGENT) .readPerfLog() .then((events) => { expect(events.length).toEqual(2); expect(events[0]) .toEqual(normEvents.start('gc', 1.0, {'usedHeapSize': 1000, 'majorGc': true})); expect(events[1]) .toEqual(normEvents.end('gc', 2.0, {'usedHeapSize': 0, 'majorGc': true})); async.done(); }); })); ['Layout', 'UpdateLayerTree', 'Paint'].forEach((recordType) => { it(`should report ${recordType} as "render"`, inject([AsyncTestCompleter], (async) => { createExtension( [ chrome45TimelineEvents.start(recordType, 1234), chrome45TimelineEvents.end(recordType, 2345) ], CHROME45_USER_AGENT) .readPerfLog() .then((events) => { expect(events).toEqual([ normEvents.start('render', 1.234), normEvents.end('render', 2.345), ]); async.done(); }); })); }); it(`should report UpdateLayoutTree as "render"`, inject([AsyncTestCompleter], (async) => { createExtension( [ chromeBlinkTimelineEvents.start('UpdateLayoutTree', 1234), chromeBlinkTimelineEvents.end('UpdateLayoutTree', 2345) ], CHROME45_USER_AGENT) .readPerfLog() .then((events) => { expect(events).toEqual([ normEvents.start('render', 1.234), normEvents.end('render', 2.345), ]); async.done(); }); })); it('should ignore FunctionCalls from webdriver', inject([AsyncTestCompleter], (async) => { createExtension([ chromeTimelineV8Events.start('FunctionCall', 0, {'data': {'scriptName': 'InjectedScript'}}) ]) .readPerfLog() .then((events) => { expect(events).toEqual([]); async.done(); }); })); it('should ignore FunctionCalls with empty scriptName', inject([AsyncTestCompleter], (async) => { createExtension( [chromeTimelineV8Events.start('FunctionCall', 0, {'data': {'scriptName': ''}})]) .readPerfLog() .then((events) => { expect(events).toEqual([]); async.done(); }); })); it('should report navigationStart', inject([AsyncTestCompleter], (async) => { createExtension([chromeBlinkUserTimingEvents.start('navigationStart', 1234)], CHROME45_USER_AGENT) .readPerfLog() .then((events) => { expect(events).toEqual([normEvents.start('navigationStart', 1.234)]); async.done(); }); })); it('should report receivedData', inject([AsyncTestCompleter], (async) => { createExtension( [ chrome45TimelineEvents.instant('ResourceReceivedData', 1234, {'data': {'encodedDataLength': 987}}) ], CHROME45_USER_AGENT) .readPerfLog() .then((events) => { expect(events).toEqual( [normEvents.instant('receivedData', 1.234, {'encodedDataLength': 987})]); async.done(); }); })); it('should report sendRequest', inject([AsyncTestCompleter], (async) => { createExtension( [ chrome45TimelineEvents.instant( 'ResourceSendRequest', 1234, {'data': {'url': 'http://here', 'requestMethod': 'GET'}}) ], CHROME45_USER_AGENT) .readPerfLog() .then((events) => { expect(events).toEqual([ normEvents.instant('sendRequest', 1.234, {'url': 'http://here', 'method': 'GET'}) ]); async.done(); }); })); }); describe('readPerfLog (common)', () => { it('should execute a dummy script before reading them', inject([AsyncTestCompleter], (async) => { // TODO(tbosch): This seems to be a bug in ChromeDriver: // Sometimes it does not report the newest events of the performance log // to the WebDriver client unless a script is executed... createExtension([]).readPerfLog().then((_) => { expect(log).toEqual([['executeScript', '1+1'], ['logs', 'performance']]); async.done(); }); })); ['Rasterize', 'CompositeLayers'].forEach((recordType) => { it(`should report ${recordType} as "render"`, inject([AsyncTestCompleter], (async) => { createExtension( [ chromeTimelineEvents.start(recordType, 1234), chromeTimelineEvents.end(recordType, 2345) ], CHROME45_USER_AGENT) .readPerfLog() .then((events) => { expect(events).toEqual([ normEvents.start('render', 1.234), normEvents.end('render', 2.345), ]); async.done(); }); })); }); describe('frame metrics', () => { it('should report ImplThreadRenderingStats as frame event', inject([AsyncTestCompleter], (async) => { createExtension([ benchmarkEvents.instant('BenchmarkInstrumentation::ImplThreadRenderingStats', 1100, {'data': {'frame_count': 1}}) ]) .readPerfLog() .then((events) => { expect(events).toEqual([ normEvents.create('i', 'frame', 1.1), ]); async.done(); }); })); it('should not report ImplThreadRenderingStats with zero frames', inject([AsyncTestCompleter], (async) => { createExtension([ benchmarkEvents.instant('BenchmarkInstrumentation::ImplThreadRenderingStats', 1100, {'data': {'frame_count': 0}}) ]) .readPerfLog() .then((events) => { expect(events).toEqual([]); async.done(); }); })); it('should throw when ImplThreadRenderingStats contains more than one frame', inject([AsyncTestCompleter], (async) => { PromiseWrapper.catchError( createExtension([ benchmarkEvents.instant('BenchmarkInstrumentation::ImplThreadRenderingStats', 1100, {'data': {'frame_count': 2}}) ]).readPerfLog(), (err) => { expect(() => { throw err; }) .toThrowError('multi-frame render stats not supported'); async.done(); }); })); }); it('should report begin timestamps', inject([AsyncTestCompleter], (async) => { createExtension([blinkEvents.create('S', 'someName', 1000)]) .readPerfLog() .then((events) => { expect(events).toEqual([normEvents.markStart('someName', 1.0)]); async.done(); }); })); it('should report end timestamps', inject([AsyncTestCompleter], (async) => { createExtension([blinkEvents.create('F', 'someName', 1000)]) .readPerfLog() .then((events) => { expect(events).toEqual([normEvents.markEnd('someName', 1.0)]); async.done(); }); })); it('should throw an error on buffer overflow', inject([AsyncTestCompleter], (async) => { PromiseWrapper.catchError( createExtension( [ chromeTimelineEvents.start('FunctionCall', 1234), ], CHROME45_USER_AGENT, 'Tracing.bufferUsage') .readPerfLog(), (err) => { expect(() => { throw err; }) .toThrowError('The DevTools trace buffer filled during the test!'); async.done(); }); })); it('should match chrome browsers', () => { expect(createExtension().supports({'browserName': 'chrome'})).toBe(true); expect(createExtension().supports({'browserName': 'Chrome'})).toBe(true); }); }); });
describe('DirectiveNormalizer', () => { var dirType: CompileTypeMetadata; beforeEachProviders(() => TEST_PROVIDERS); beforeEach(() => { dirType = new CompileTypeMetadata({name: 'SomeComp'}); }); describe('loadTemplate', () => { describe('inline template', () => { it('should store the template', inject([AsyncTestCompleter, DirectiveNormalizer], (async, normalizer: DirectiveNormalizer) => { normalizer.normalizeTemplate(dirType, new CompileTemplateMetadata({ encapsulation: null, template: 'a', templateUrl: null, styles: [], styleUrls: ['test.css'], baseUrl: 'package:some/module/a.js' })) .then((template: CompileTemplateMetadata) => { expect(template.template).toEqual('a'); expect(template.templateUrl).toEqual('package:some/module/a.js'); async.done(); }); })); it('should resolve styles on the annotation against the baseUrl', inject([AsyncTestCompleter, DirectiveNormalizer], (async, normalizer: DirectiveNormalizer) => { normalizer.normalizeTemplate(dirType, new CompileTemplateMetadata({ encapsulation: null, template: '', templateUrl: null, styles: [], styleUrls: ['test.css'], baseUrl: 'package:some/module/a.js' })) .then((template: CompileTemplateMetadata) => { expect(template.styleUrls).toEqual(['package:some/module/test.css']); async.done(); }); })); it('should resolve styles in the template against the baseUrl', inject([AsyncTestCompleter, DirectiveNormalizer], (async, normalizer: DirectiveNormalizer) => { normalizer.normalizeTemplate(dirType, new CompileTemplateMetadata({ encapsulation: null, template: '<style>@import test.css</style>', templateUrl: null, styles: [], styleUrls: [], baseUrl: 'package:some/module/a.js' })) .then((template: CompileTemplateMetadata) => { expect(template.styleUrls).toEqual(['package:some/module/test.css']); async.done(); }); })); }); describe('templateUrl', () => { it('should load a template from a url that is resolved against baseUrl', inject([AsyncTestCompleter, DirectiveNormalizer, XHR], (async, normalizer: DirectiveNormalizer, xhr: MockXHR) => { xhr.expect('package:some/module/sometplurl.html', 'a'); normalizer.normalizeTemplate(dirType, new CompileTemplateMetadata({ encapsulation: null, template: null, templateUrl: 'sometplurl.html', styles: [], styleUrls: ['test.css'], baseUrl: 'package:some/module/a.js' })) .then((template: CompileTemplateMetadata) => { expect(template.template).toEqual('a'); expect(template.templateUrl) .toEqual('package:some/module/sometplurl.html'); async.done(); }); xhr.flush(); })); it('should resolve styles on the annotation against the baseUrl', inject([AsyncTestCompleter, DirectiveNormalizer, XHR], (async, normalizer: DirectiveNormalizer, xhr: MockXHR) => { xhr.expect('package:some/module/tpl/sometplurl.html', ''); normalizer.normalizeTemplate(dirType, new CompileTemplateMetadata({ encapsulation: null, template: null, templateUrl: 'tpl/sometplurl.html', styles: [], styleUrls: ['test.css'], baseUrl: 'package:some/module/a.js' })) .then((template: CompileTemplateMetadata) => { expect(template.styleUrls).toEqual(['package:some/module/test.css']); async.done(); }); xhr.flush(); })); it('should resolve styles in the template against the templateUrl', inject([AsyncTestCompleter, DirectiveNormalizer, XHR], (async, normalizer: DirectiveNormalizer, xhr: MockXHR) => { xhr.expect('package:some/module/tpl/sometplurl.html', '<style>@import test.css</style>'); normalizer.normalizeTemplate(dirType, new CompileTemplateMetadata({ encapsulation: null, template: null, templateUrl: 'tpl/sometplurl.html', styles: [], styleUrls: [], baseUrl: 'package:some/module/a.js' })) .then((template: CompileTemplateMetadata) => { expect(template.styleUrls).toEqual(['package:some/module/tpl/test.css']); async.done(); }); xhr.flush(); })); }); it('should throw if no template was specified', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { expect(() => normalizer.normalizeTemplate( dirType, new CompileTemplateMetadata( {encapsulation: null, styles: [], styleUrls: []}))) .toThrowError('No template specified for component SomeComp'); })); }); describe('normalizeLoadedTemplate', () => { it('should store the viewEncapsulationin the result', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var viewEncapsulation = ViewEncapsulation.Native; var template = normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ encapsulation: viewEncapsulation, styles: [], styleUrls: [], baseUrl: 'package:some/module/a.js' }), '', 'package:some/module/'); expect(template.encapsulation).toBe(viewEncapsulation); })); it('should keep the template as html', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var template = normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ encapsulation: null, styles: [], styleUrls: [], baseUrl: 'package:some/module/a.js' }), 'a', 'package:some/module/'); expect(template.template).toEqual('a') })); it('should collect ngContent', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var template = normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ encapsulation: null, styles: [], styleUrls: [], baseUrl: 'package:some/module/a.js' }), '<ng-content select="a"></ng-content>', 'package:some/module/'); expect(template.ngContentSelectors).toEqual(['a']); })); it('should normalize ngContent wildcard selector', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var template = normalizer.normalizeLoadedTemplate( dirType, new CompileTemplateMetadata({ encapsulation: null, styles: [], styleUrls: [], baseUrl: 'package:some/module/a.js' }), '<ng-content></ng-content><ng-content select></ng-content><ng-content select="*"></ng-content>', 'package:some/module/'); expect(template.ngContentSelectors).toEqual(['*', '*', '*']); })); it('should collect top level styles in the template', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var template = normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ encapsulation: null, styles: [], styleUrls: [], baseUrl: 'package:some/module/a.js' }), '<style>a</style>', 'package:some/module/'); expect(template.styles).toEqual(['a']); })); it('should collect styles inside in elements', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var template = normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ encapsulation: null, styles: [], styleUrls: [], baseUrl: 'package:some/module/a.js' }), '<div><style>a</style></div>', 'package:some/module/'); expect(template.styles).toEqual(['a']); })); it('should collect styleUrls in the template', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var template = normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ encapsulation: null, styles: [], styleUrls: [], baseUrl: 'package:some/module/a.js' }), '<link rel="stylesheet" href="aUrl">', 'package:some/module/'); expect(template.styleUrls).toEqual(['package:some/module/aUrl']); })); it('should collect styleUrls in elements', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var template = normalizer.normalizeLoadedTemplate( dirType, new CompileTemplateMetadata({ encapsulation: null, styles: [], styleUrls: [], baseUrl: 'package:some/module/a.js' }), '<div><link rel="stylesheet" href="aUrl"></div>', 'package:some/module/'); expect(template.styleUrls).toEqual(['package:some/module/aUrl']); })); it('should ignore link elements with non stylesheet rel attribute', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var template = normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ encapsulation: null, styles: [], styleUrls: [], baseUrl: 'package:some/module/a.js' }), '<link href="b" rel="a">', 'package:some/module/'); expect(template.styleUrls).toEqual([]); })); it('should ignore link elements with absolute urls but non package: scheme', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var template = normalizer.normalizeLoadedTemplate( dirType, new CompileTemplateMetadata({ encapsulation: null, styles: [], styleUrls: [], baseUrl: 'package:some/module/a.js' }), '<link href="http://some/external.css" rel="stylesheet">', 'package:some/module/'); expect(template.styleUrls).toEqual([]); })); it('should extract @import style urls into styleAbsUrl', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var template = normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ encapsulation: null, styles: ['@import "test.css";'], styleUrls: [], baseUrl: 'package:some/module/a.js' }), '', 'package:some/module/id'); expect(template.styles).toEqual(['']); expect(template.styleUrls).toEqual(['package:some/module/test.css']); })); it('should not resolve relative urls in inline styles', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var template = normalizer.normalizeLoadedTemplate( dirType, new CompileTemplateMetadata({ encapsulation: null, styles: ['.foo{background-image: url(\'double.jpg\');'], styleUrls: [], baseUrl: 'package:some/module/a.js' }), '', 'package:some/module/id'); expect(template.styles).toEqual(['.foo{background-image: url(\'double.jpg\');']); })); it('should resolve relative style urls in styleUrls', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var template = normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ encapsulation: null, styles: [], styleUrls: ['test.css'], baseUrl: 'package:some/module/a.js' }), '', 'package:some/module/id'); expect(template.styles).toEqual([]); expect(template.styleUrls).toEqual(['package:some/module/test.css']); })); it('should resolve relative style urls in styleUrls with http directive url', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var template = normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ encapsulation: null, styles: [], styleUrls: ['test.css'], baseUrl: 'http://some/module/a.js' }), '', 'http://some/module/id'); expect(template.styles).toEqual([]); expect(template.styleUrls).toEqual(['http://some/module/test.css']); })); it('should normalize ViewEncapsulation.Emulated to ViewEncapsulation.None if there are no styles nor stylesheets', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var template = normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ encapsulation: ViewEncapsulation.Emulated, styles: [], styleUrls: [], baseUrl: 'package:some/module/a.js' }), '', 'package:some/module/id'); expect(template.encapsulation).toEqual(ViewEncapsulation.None); })); it('should ignore ng-content in elements with ngNonBindable', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var template = normalizer.normalizeLoadedTemplate( dirType, new CompileTemplateMetadata({ encapsulation: null, styles: [], styleUrls: [], baseUrl: 'package:some/module/a.js' }), '<div ngNonBindable><ng-content select="a"></ng-content></div>', 'package:some/module/'); expect(template.ngContentSelectors).toEqual([]); })); it('should still collect <style> in elements with ngNonBindable', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var template = normalizer.normalizeLoadedTemplate( dirType, new CompileTemplateMetadata({ encapsulation: null, styles: [], styleUrls: [], baseUrl: 'package:some/module/a.js' }), '<div ngNonBindable><style>div {color:red}</style></div>', 'package:some/module/'); expect(template.styles).toEqual(['div {color:red}']); })); }); });