/** * @license * Copyright Google Inc. All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ 'use strict'; describe('navigation', function () { var elt, $compile, $rootScope, $rootRouter, $compileProvider; beforeEach(function () { module('ng'); module('ngComponentRouter'); module(function (_$compileProvider_) { $compileProvider = _$compileProvider_; }); inject(function (_$compile_, _$rootScope_, _$rootRouter_) { $compile = _$compile_; $rootScope = _$rootScope_; $rootRouter = _$rootRouter_; }); registerDirective('userCmp', { template: '
hello {{userCmp.$routeParams.name}}
', $routerOnActivate: function(next) { this.$routeParams = next.params; } }); registerDirective('oneCmp', { template: '
{{oneCmp.number}}
', controller: function () {this.number = 'one';} }); registerDirective('twoCmp', { template: '
{{twoCmp.number}}
', controller: function () {this.number = 'two';} }); registerComponent('threeCmp', { template: '
{{$ctrl.number}}
', controller: function () {this.number = 'three';} }); registerComponent('getParams', { template: '
{{$ctrl.params.x}}
', controller: function () { this.$routerOnActivate = function(next) { this.params = next.params; }; } }); }); it('should work in a simple case', function () { compile(''); $rootRouter.config([ { path: '/', component: 'oneCmp' } ]); $rootRouter.navigateByUrl('/'); $rootScope.$digest(); expect(elt.text()).toBe('one'); }); it('should work with components created by the `mod.component()` helper', function () { compile(''); $rootRouter.config([ { path: '/', component: 'threeCmp' } ]); $rootRouter.navigateByUrl('/'); $rootScope.$digest(); expect(elt.text()).toBe('three'); }); it('should navigate between components with different parameters', function () { $rootRouter.config([ { path: '/user/:name', component: 'userCmp' } ]); compile(''); $rootRouter.navigateByUrl('/user/brian'); $rootScope.$digest(); expect(elt.text()).toBe('hello brian'); $rootRouter.navigateByUrl('/user/igor'); $rootScope.$digest(); expect(elt.text()).toBe('hello igor'); }); it('should reuse a parent when navigating between child components with different parameters', function () { var instanceCount = 0; function ParentController() { instanceCount += 1; } registerDirective('parentCmp', { template: 'parent { }', $routeConfig: [ { path: '/user/:name', component: 'userCmp' } ], controller: ParentController }); $rootRouter.config([ { path: '/parent/...', component: 'parentCmp' } ]); compile(''); $rootRouter.navigateByUrl('/parent/user/brian'); $rootScope.$digest(); expect(instanceCount).toBe(1); expect(elt.text()).toBe('parent { hello brian }'); $rootRouter.navigateByUrl('/parent/user/igor'); $rootScope.$digest(); expect(instanceCount).toBe(1); expect(elt.text()).toBe('parent { hello igor }'); }); it('should work with nested outlets', function () { registerDirective('childCmp', { template: '
inner {
}
', $routeConfig: [ { path: '/b', component: 'oneCmp' } ] }); $rootRouter.config([ { path: '/a/...', component: 'childCmp' } ]); compile('
outer {
}
'); $rootRouter.navigateByUrl('/a/b'); $rootScope.$digest(); expect(elt.text()).toBe('outer { inner { one } }'); }); it('should work when parent route has empty path', inject(function ($location) { registerComponent('childCmp', { template: '
inner {
}
', $routeConfig: [ { path: '/b', component: 'oneCmp' } ] }); $rootRouter.config([ { path: '/...', component: 'childCmp' } ]); compile('
outer {
}
'); $rootRouter.navigateByUrl('/b'); $rootScope.$digest(); expect(elt.text()).toBe('outer { inner { one } }'); expect($location.path()).toBe('/b'); })); it('should work with recursive nested outlets', function () { registerDirective('recurCmp', { template: '
recur {
}
', $routeConfig: [ { path: '/recur', component: 'recurCmp' }, { path: '/end', component: 'oneCmp' } ]}); $rootRouter.config([ { path: '/recur', component: 'recurCmp' }, { path: '/', component: 'oneCmp' } ]); compile('
root {
}
'); $rootRouter.navigateByUrl('/recur/recur/end'); $rootScope.$digest(); expect(elt.text()).toBe('root { one }'); }); it('should change location path', inject(function ($location) { $rootRouter.config([ { path: '/user', component: 'userCmp' } ]); compile('
'); $rootRouter.navigateByUrl('/user'); $rootScope.$digest(); expect($location.path()).toBe('/user'); })); it('should pass through query terms to the location', inject(function ($location) { $rootRouter.config([ { path: '/user', component: 'userCmp' } ]); compile('
'); $rootRouter.navigateByUrl('/user?x=y'); $rootScope.$digest(); expect($location.path()).toBe('/user'); expect($location.search()).toEqual({ x: 'y'}); })); it('should change location to the canonical route', inject(function ($location) { compile('
'); $rootRouter.config([ { path: '/', redirectTo: ['/User'] }, { path: '/user', component: 'userCmp', name: 'User' } ]); $rootRouter.navigateByUrl('/'); $rootScope.$digest(); expect($location.path()).toBe('/user'); })); it('should change location to the canonical route with nested components', inject(function ($location) { registerDirective('childRouter', { template: '
inner {
}
', $routeConfig: [ { path: '/new-child', component: 'oneCmp', name: 'NewChild'}, { path: '/new-child-two', component: 'twoCmp', name: 'NewChildTwo'} ] }); $rootRouter.config([ { path: '/old-parent/old-child', redirectTo: ['/NewParent', 'NewChild'] }, { path: '/old-parent/old-child-two', redirectTo: ['/NewParent', 'NewChildTwo'] }, { path: '/new-parent/...', component: 'childRouter', name: 'NewParent' } ]); compile('
'); $rootRouter.navigateByUrl('/old-parent/old-child'); $rootScope.$digest(); expect($location.path()).toBe('/new-parent/new-child'); expect(elt.text()).toBe('inner { one }'); $rootRouter.navigateByUrl('/old-parent/old-child-two'); $rootScope.$digest(); expect($location.path()).toBe('/new-parent/new-child-two'); expect(elt.text()).toBe('inner { two }'); })); it('should navigate when the location path changes', inject(function ($location) { $rootRouter.config([ { path: '/one', component: 'oneCmp' } ]); compile('
'); $location.path('/one'); $rootScope.$digest(); expect(elt.text()).toBe('one'); })); it('should navigate when the location query changes', inject(function ($location) { $rootRouter.config([ { path: '/get/params', component: 'getParams' } ]); compile('
'); $location.url('/get/params?x=y'); $rootScope.$digest(); expect(elt.text()).toBe('y'); })); it('should expose a "navigating" property on $rootRouter', inject(function ($q) { var defer; registerDirective('pendingActivate', { $canActivate: function () { defer = $q.defer(); return defer.promise; } }); $rootRouter.config([ { path: '/pending-activate', component: 'pendingActivate' } ]); compile('
'); $rootRouter.navigateByUrl('/pending-activate'); $rootScope.$digest(); expect($rootRouter.navigating).toBe(true); defer.resolve(); $rootScope.$digest(); expect($rootRouter.navigating).toBe(false); })); function registerDirective(name, options) { var controller = getController(options); function factory() { return { template: options.template || '', controllerAs: name, controller: controller }; } applyStaticProperties(controller, options); $compileProvider.directive(name, factory); } function registerComponent(name, options) { var definition = { template: options.template || '', controller: getController(options), }; applyStaticProperties(definition.controller, options); $compileProvider.component(name, definition); } function compile(template) { elt = $compile('
' + template + '
')($rootScope); $rootScope.$digest(); return elt; } function getController(options) { var controller = options.controller || function () {}; [ '$routerOnActivate', '$routerOnDeactivate', '$routerOnReuse', '$routerCanReuse', '$routerCanDeactivate' ].forEach(function (hookName) { if (options[hookName]) { controller.prototype[hookName] = options[hookName]; } }); return controller; } function applyStaticProperties(target, options) { ['$canActivate', '$routeConfig'].forEach(function(property) { if (options[property]) { target[property] = options[property]; } }); } });