fix(router): ensure navigation via back button works

The router will now navigate and respect the current address value
accordingly whenever a popState event is handled.

Closes #2201
This commit is contained in:
Matias Niemelä
2015-07-28 01:46:09 -04:00
parent 60f38eab78
commit 7bf7ec6d9c
5 changed files with 99 additions and 14 deletions
@@ -88,6 +88,8 @@ export function main() {
var locationStrategy = new MockLocationStrategy();
var location = new Location(locationStrategy);
function assertUrl(path) { expect(location.path()).toEqual(path); }
location.go('/ready');
assertUrl('/ready');
@@ -102,8 +104,6 @@ export function main() {
location.back();
assertUrl('/ready');
function assertUrl(path) { expect(location.path()).toEqual(path); }
});
});
}
@@ -27,7 +27,8 @@ import {
RouteParams,
Router,
appBaseHrefToken,
routerDirectives
routerDirectives,
HashLocationStrategy
} from 'angular2/router';
import {LocationStrategy} from 'angular2/src/router/location_strategy';
@@ -81,6 +82,57 @@ export function main() {
}));
});
describe('back button app', () => {
beforeEachBindings(() => { return [bind(appComponentTypeToken).toValue(HierarchyAppCmp)]; });
it('should change the url without pushing a new history state for back navigations',
inject([AsyncTestCompleter, TestComponentBuilder], (async, tcb: TestComponentBuilder) => {
tcb.createAsync(HierarchyAppCmp)
.then((rootTC) => {
var router = rootTC.componentInstance.router;
var position = 0;
var flipped = false;
var history =
[
['/parent/child', 'root { parent { hello } }', '/super-parent/child'],
['/super-parent/child', 'root { super-parent { hello2 } }', '/parent/child'],
['/parent/child', 'root { parent { hello } }', false]
]
router.subscribe((_) => {
var location = rootTC.componentInstance.location;
var element = rootTC.nativeElement;
var path = location.path();
var entry = history[position];
expect(path).toEqual(entry[0]);
expect(element).toHaveText(entry[1]);
var nextUrl = entry[2];
if (nextUrl == false) {
flipped = true;
}
if (flipped && position == 0) {
async.done();
return;
}
position = position + (flipped ? -1 : 1);
if (flipped) {
location.back();
} else {
router.navigate(nextUrl);
}
});
router.navigate(history[0][0]);
});
}));
});
describe('hierarchical app', () => {
beforeEachBindings(() => { return [bind(appComponentTypeToken).toValue(HierarchyAppCmp)]; });
@@ -153,6 +205,11 @@ export function main() {
class HelloCmp {
}
@Component({selector: 'hello2-cmp'})
@View({template: 'hello2'})
class Hello2Cmp {
}
@Component({selector: 'app-cmp'})
@View({template: "outer { <router-outlet></router-outlet> }", directives: routerDirectives})
@RouteConfig([new Route({path: '/', component: HelloCmp})])
@@ -166,9 +223,18 @@ class AppCmp {
class ParentCmp {
}
@Component({selector: 'super-parent-cmp'})
@View({template: `super-parent { <router-outlet></router-outlet> }`, directives: routerDirectives})
@RouteConfig([new Route({path: '/child', component: Hello2Cmp})])
class SuperParentCmp {
}
@Component({selector: 'app-cmp'})
@View({template: `root { <router-outlet></router-outlet> }`, directives: routerDirectives})
@RouteConfig([new Route({path: '/parent/...', component: ParentCmp})])
@RouteConfig([
new Route({path: '/parent/...', component: ParentCmp}),
new Route({path: '/super-parent/...', component: SuperParentCmp})
])
class HierarchyAppCmp {
constructor(public router: Router, public location: LocationStrategy) {}
}
@@ -76,6 +76,20 @@ export function main() {
});
}));
it('should not push a history change on when navigate is called with skipUrlChange',
inject([AsyncTestCompleter], (async) => {
var outlet = makeDummyOutlet();
router.registerOutlet(outlet)
.then((_) => router.config([new Route({path: '/b', component: DummyComponent})]))
.then((_) => router.navigate('/b', true))
.then((_) => {
expect(outlet.spy('commit')).toHaveBeenCalled();
expect(location.urlChanges).toEqual([]);
async.done();
});
}));
it('should navigate after being configured', inject([AsyncTestCompleter], (async) => {
var outlet = makeDummyOutlet();