'use strict'; describe('navigation', function () { var elt, $compile, $rootScope, $router, $compileProvider; beforeEach(function () { module('ng'); module('ngComponentRouter'); module(function (_$compileProvider_) { $compileProvider = _$compileProvider_; }); inject(function (_$compile_, _$rootScope_, _$router_) { $compile = _$compile_; $rootScope = _$rootScope_; $router = _$router_; }); registerComponent('userCmp', { template: '
hello {{userCmp.$routeParams.name}}
' }); registerComponent('oneCmp', { template: '
{{oneCmp.number}}
', controller: function () {this.number = 'one'} }); registerComponent('twoCmp', { template: '
{{twoCmp.number}}
', controller: function () {this.number = 'two'} }); }); it('should work in a simple case', function () { compile(''); $router.config([ { path: '/', component: 'oneCmp' } ]); $router.navigateByUrl('/'); $rootScope.$digest(); expect(elt.text()).toBe('one'); }); it('should navigate between components with different parameters', function () { $router.config([ { path: '/user/:name', component: 'userCmp' } ]); compile(''); $router.navigateByUrl('/user/brian'); $rootScope.$digest(); expect(elt.text()).toBe('hello brian'); $router.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; } registerComponent('parentCmp', { template: 'parent { }', $routeConfig: [ { path: '/user/:name', component: 'userCmp' } ], controller: ParentController }); $router.config([ { path: '/parent/...', component: 'parentCmp' } ]); compile(''); $router.navigateByUrl('/parent/user/brian'); $rootScope.$digest(); expect(instanceCount).toBe(1); expect(elt.text()).toBe('parent { hello brian }'); $router.navigateByUrl('/parent/user/igor'); $rootScope.$digest(); expect(instanceCount).toBe(1); expect(elt.text()).toBe('parent { hello igor }'); }); it('should work with nested outlets', function () { registerComponent('childCmp', { template: '
inner {
}
', $routeConfig: [ { path: '/b', component: 'oneCmp' } ] }); $router.config([ { path: '/a/...', component: 'childCmp' } ]); compile('
outer {
}
'); $router.navigateByUrl('/a/b'); $rootScope.$digest(); expect(elt.text()).toBe('outer { inner { one } }'); }); // TODO: fix this xit('should work with recursive nested outlets', function () { registerComponent('recurCmp', { template: '
recur {
}
', $routeConfig: [ { path: '/recur', component: 'recurCmp' }, { path: '/end', component: 'oneCmp' } ]}); $router.config([ { path: '/recur', component: 'recurCmp' }, { path: '/', component: 'oneCmp' } ]); compile('
root {
}
'); $router.navigateByUrl('/recur/recur/end'); $rootScope.$digest(); expect(elt.text()).toBe('root { one }'); }); it('should change location path', inject(function ($location) { $router.config([ { path: '/user', component: 'userCmp' } ]); compile('
'); $router.navigateByUrl('/user'); $rootScope.$digest(); expect($location.path()).toBe('/user'); })); it('should change location to the canonical route', inject(function ($location) { compile('
'); $router.config([ { path: '/', redirectTo: '/user' }, { path: '/user', component: 'userCmp' } ]); $router.navigateByUrl('/'); $rootScope.$digest(); expect($location.path()).toBe('/user'); })); it('should change location to the canonical route with nested components', inject(function ($location) { registerComponent('childRouter', { template: '
inner {
}
', $routeConfig: [ { path: '/old-child', redirectTo: '/new-child' }, { path: '/new-child', component: 'oneCmp'}, { path: '/old-child-two', redirectTo: '/new-child-two' }, { path: '/new-child-two', component: 'twoCmp'} ] }); $router.config([ { path: '/old-parent', redirectTo: '/new-parent' }, { path: '/new-parent/...', component: 'childRouter' } ]); compile('
'); $router.navigateByUrl('/old-parent/old-child'); $rootScope.$digest(); expect($location.path()).toBe('/new-parent/new-child'); expect(elt.text()).toBe('inner { one }'); $router.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) { $router.config([ { path: '/one', component: 'oneCmp' } ]); compile('
'); $location.path('/one'); $rootScope.$digest(); expect(elt.text()).toBe('one'); })); it('should expose a "navigating" property on $router', inject(function ($q) { var defer; registerComponent('pendingActivate', { $canActivate: function () { defer = $q.defer(); return defer.promise; } }); $router.config([ { path: '/pending-activate', component: 'pendingActivate' } ]); compile('
'); $router.navigateByUrl('/pending-activate'); $rootScope.$digest(); expect($router.navigating).toBe(true); defer.resolve(); $rootScope.$digest(); expect($router.navigating).toBe(false); })); function registerComponent(name, options) { var controller = options.controller || function () {}; ['$onActivate', '$onDeactivate', '$onReuse', '$canReuse', '$canDeactivate'].forEach(function (hookName) { if (options[hookName]) { controller.prototype[hookName] = options[hookName]; } }); function factory() { return { template: options.template || '', controllerAs: name, controller: controller }; } if (options.$canActivate) { factory.$canActivate = options.$canActivate; } if (options.$routeConfig) { factory.$routeConfig = options.$routeConfig; } $compileProvider.directive(name, factory); } function compile(template) { elt = $compile('
' + template + '
')($rootScope); $rootScope.$digest(); return elt; } });