feat(router): add support for APP_BASE_HREF to HashLocationStrategy

Closes #4935
Closes #5368

Closes #5451
This commit is contained in:
Brian Ford
2015-11-23 10:47:06 -08:00
parent b6ec2387b3
commit 1bec4f6c61
9 changed files with 476 additions and 47 deletions
@@ -0,0 +1,167 @@
import {
AsyncTestCompleter,
describe,
proxy,
it,
iit,
ddescribe,
expect,
inject,
beforeEach,
beforeEachProviders,
SpyObject
} from 'angular2/testing_internal';
import {Injector, provide} from 'angular2/core';
import {CONST_EXPR} from 'angular2/src/facade/lang';
import {PlatformLocation} from 'angular2/src/router/platform_location';
import {LocationStrategy, APP_BASE_HREF} from 'angular2/src/router/location_strategy';
import {HashLocationStrategy} from 'angular2/src/router/hash_location_strategy';
import {SpyPlatformLocation} from './spies';
export function main() {
describe('HashLocationStrategy', () => {
var platformLocation, locationStrategy;
beforeEachProviders(
() => [HashLocationStrategy, provide(PlatformLocation, {useClass: SpyPlatformLocation})]);
describe('without APP_BASE_HREF', () => {
beforeEach(inject([PlatformLocation, HashLocationStrategy], (pl, ls) => {
platformLocation = pl;
locationStrategy = ls;
platformLocation.spy('pushState');
platformLocation.pathname = '';
}));
it('should prepend urls with a hash for non-empty URLs', () => {
expect(locationStrategy.prepareExternalUrl('foo')).toEqual('#foo');
locationStrategy.pushState(null, 'Title', 'foo', '');
expect(platformLocation.spy('pushState')).toHaveBeenCalledWith(null, 'Title', '#foo');
});
it('should prepend urls with a hash for URLs with query params', () => {
expect(locationStrategy.prepareExternalUrl('foo?bar')).toEqual('#foo?bar');
locationStrategy.pushState(null, 'Title', 'foo', 'bar=baz');
expect(platformLocation.spy('pushState'))
.toHaveBeenCalledWith(null, 'Title', '#foo?bar=baz');
});
it('should prepend urls with a hash for URLs with just query params', () => {
expect(locationStrategy.prepareExternalUrl('?bar')).toEqual('#?bar');
locationStrategy.pushState(null, 'Title', '', 'bar=baz');
expect(platformLocation.spy('pushState')).toHaveBeenCalledWith(null, 'Title', '#?bar=baz');
});
it('should not prepend a hash to external urls for an empty internal URL', () => {
expect(locationStrategy.prepareExternalUrl('')).toEqual('');
locationStrategy.pushState(null, 'Title', '', '');
expect(platformLocation.spy('pushState')).toHaveBeenCalledWith(null, 'Title', '');
});
});
describe('with APP_BASE_HREF with neither leading nor trailing slash', () => {
beforeEachProviders(() => [provide(APP_BASE_HREF, {useValue: 'app'})]);
beforeEach(inject([PlatformLocation, HashLocationStrategy], (pl, ls) => {
platformLocation = pl;
locationStrategy = ls;
platformLocation.spy('pushState');
platformLocation.pathname = '';
}));
it('should prepend urls with a hash for non-empty URLs', () => {
expect(locationStrategy.prepareExternalUrl('foo')).toEqual('#app/foo');
locationStrategy.pushState(null, 'Title', 'foo', '');
expect(platformLocation.spy('pushState')).toHaveBeenCalledWith(null, 'Title', '#app/foo');
});
it('should prepend urls with a hash for URLs with query params', () => {
expect(locationStrategy.prepareExternalUrl('foo?bar')).toEqual('#app/foo?bar');
locationStrategy.pushState(null, 'Title', 'foo', 'bar=baz');
expect(platformLocation.spy('pushState'))
.toHaveBeenCalledWith(null, 'Title', '#app/foo?bar=baz');
});
it('should not prepend a hash to external urls for an empty internal URL', () => {
expect(locationStrategy.prepareExternalUrl('')).toEqual('#app');
locationStrategy.pushState(null, 'Title', '', '');
expect(platformLocation.spy('pushState')).toHaveBeenCalledWith(null, 'Title', '#app');
});
});
describe('with APP_BASE_HREF with leading slash', () => {
beforeEachProviders(() => [provide(APP_BASE_HREF, {useValue: '/app'})]);
beforeEach(inject([PlatformLocation, HashLocationStrategy], (pl, ls) => {
platformLocation = pl;
locationStrategy = ls;
platformLocation.spy('pushState');
platformLocation.pathname = '';
}));
it('should prepend urls with a hash for non-empty URLs', () => {
expect(locationStrategy.prepareExternalUrl('foo')).toEqual('#/app/foo');
locationStrategy.pushState(null, 'Title', 'foo', '');
expect(platformLocation.spy('pushState')).toHaveBeenCalledWith(null, 'Title', '#/app/foo');
});
it('should prepend urls with a hash for URLs with query params', () => {
expect(locationStrategy.prepareExternalUrl('foo?bar')).toEqual('#/app/foo?bar');
locationStrategy.pushState(null, 'Title', 'foo', 'bar=baz');
expect(platformLocation.spy('pushState'))
.toHaveBeenCalledWith(null, 'Title', '#/app/foo?bar=baz');
});
it('should not prepend a hash to external urls for an empty internal URL', () => {
expect(locationStrategy.prepareExternalUrl('')).toEqual('#/app');
locationStrategy.pushState(null, 'Title', '', '');
expect(platformLocation.spy('pushState')).toHaveBeenCalledWith(null, 'Title', '#/app');
});
});
describe('with APP_BASE_HREF with both leading and trailing slash', () => {
beforeEachProviders(() => [provide(APP_BASE_HREF, {useValue: '/app/'})]);
beforeEach(inject([PlatformLocation, HashLocationStrategy], (pl, ls) => {
platformLocation = pl;
locationStrategy = ls;
platformLocation.spy('pushState');
platformLocation.pathname = '';
}));
it('should prepend urls with a hash for non-empty URLs', () => {
expect(locationStrategy.prepareExternalUrl('foo')).toEqual('#/app/foo');
locationStrategy.pushState(null, 'Title', 'foo', '');
expect(platformLocation.spy('pushState')).toHaveBeenCalledWith(null, 'Title', '#/app/foo');
});
it('should prepend urls with a hash for URLs with query params', () => {
expect(locationStrategy.prepareExternalUrl('foo?bar')).toEqual('#/app/foo?bar');
locationStrategy.pushState(null, 'Title', 'foo', 'bar=baz');
expect(platformLocation.spy('pushState'))
.toHaveBeenCalledWith(null, 'Title', '#/app/foo?bar=baz');
});
it('should not prepend a hash to external urls for an empty internal URL', () => {
expect(locationStrategy.prepareExternalUrl('')).toEqual('#/app/');
locationStrategy.pushState(null, 'Title', '', '');
expect(platformLocation.spy('pushState')).toHaveBeenCalledWith(null, 'Title', '#/app/');
});
});
});
}
@@ -0,0 +1,178 @@
import {
AsyncTestCompleter,
describe,
proxy,
it,
iit,
ddescribe,
expect,
inject,
beforeEach,
beforeEachProviders,
SpyObject
} from 'angular2/testing_internal';
import {Injector, provide} from 'angular2/core';
import {CONST_EXPR} from 'angular2/src/facade/lang';
import {PlatformLocation} from 'angular2/src/router/platform_location';
import {LocationStrategy, APP_BASE_HREF} from 'angular2/src/router/location_strategy';
import {PathLocationStrategy} from 'angular2/src/router/path_location_strategy';
import {SpyPlatformLocation} from './spies';
export function main() {
describe('PathLocationStrategy', () => {
var platformLocation, locationStrategy;
beforeEachProviders(() => [
PathLocationStrategy,
provide(PlatformLocation, {useFactory: makeSpyPlatformLocation})
]);
it('should throw without a base element or APP_BASE_HREF', () => {
platformLocation = new SpyPlatformLocation();
platformLocation.pathname = '';
platformLocation.spy('getBaseHrefFromDOM').andReturn(null);
expect(() => new PathLocationStrategy(platformLocation))
.toThrowError(
'No base href set. Please provide a value for the APP_BASE_HREF token or add a base element to the document.');
});
describe('without APP_BASE_HREF', () => {
beforeEach(inject([PlatformLocation, PathLocationStrategy], (pl, ls) => {
platformLocation = pl;
locationStrategy = ls;
}));
it('should prepend urls with a hash for non-empty URLs', () => {
expect(locationStrategy.prepareExternalUrl('foo')).toEqual('foo');
locationStrategy.pushState(null, 'Title', 'foo', '');
expect(platformLocation.spy('pushState')).toHaveBeenCalledWith(null, 'Title', 'foo');
});
it('should prepend urls with a hash for URLs with query params', () => {
expect(locationStrategy.prepareExternalUrl('foo?bar')).toEqual('foo?bar');
locationStrategy.pushState(null, 'Title', 'foo', 'bar=baz');
expect(platformLocation.spy('pushState'))
.toHaveBeenCalledWith(null, 'Title', 'foo?bar=baz');
});
it('should not prepend a hash to external urls for an empty internal URL', () => {
expect(locationStrategy.prepareExternalUrl('')).toEqual('');
locationStrategy.pushState(null, 'Title', '', '');
expect(platformLocation.spy('pushState')).toHaveBeenCalledWith(null, 'Title', '');
});
});
describe('with APP_BASE_HREF with neither leading nor trailing slash', () => {
beforeEachProviders(() => [provide(APP_BASE_HREF, {useValue: 'app'})]);
beforeEach(inject([PlatformLocation, PathLocationStrategy], (pl, ls) => {
platformLocation = pl;
locationStrategy = ls;
platformLocation.spy('pushState');
platformLocation.pathname = '';
}));
it('should prepend urls with a hash for non-empty URLs', () => {
expect(locationStrategy.prepareExternalUrl('foo')).toEqual('app/foo');
locationStrategy.pushState(null, 'Title', 'foo', '');
expect(platformLocation.spy('pushState')).toHaveBeenCalledWith(null, 'Title', 'app/foo');
});
it('should prepend urls with a hash for URLs with query params', () => {
expect(locationStrategy.prepareExternalUrl('foo?bar')).toEqual('app/foo?bar');
locationStrategy.pushState(null, 'Title', 'foo', 'bar=baz');
expect(platformLocation.spy('pushState'))
.toHaveBeenCalledWith(null, 'Title', 'app/foo?bar=baz');
});
it('should not prepend a hash to external urls for an empty internal URL', () => {
expect(locationStrategy.prepareExternalUrl('')).toEqual('app');
locationStrategy.pushState(null, 'Title', '', '');
expect(platformLocation.spy('pushState')).toHaveBeenCalledWith(null, 'Title', 'app');
});
});
describe('with APP_BASE_HREF with leading slash', () => {
beforeEachProviders(() => [provide(APP_BASE_HREF, {useValue: '/app'})]);
beforeEach(inject([PlatformLocation, PathLocationStrategy], (pl, ls) => {
platformLocation = pl;
locationStrategy = ls;
platformLocation.spy('pushState');
platformLocation.pathname = '';
}));
it('should prepend urls with a hash for non-empty URLs', () => {
expect(locationStrategy.prepareExternalUrl('foo')).toEqual('/app/foo');
locationStrategy.pushState(null, 'Title', 'foo', '');
expect(platformLocation.spy('pushState')).toHaveBeenCalledWith(null, 'Title', '/app/foo');
});
it('should prepend urls with a hash for URLs with query params', () => {
expect(locationStrategy.prepareExternalUrl('foo?bar')).toEqual('/app/foo?bar');
locationStrategy.pushState(null, 'Title', 'foo', 'bar=baz');
expect(platformLocation.spy('pushState'))
.toHaveBeenCalledWith(null, 'Title', '/app/foo?bar=baz');
});
it('should not prepend a hash to external urls for an empty internal URL', () => {
expect(locationStrategy.prepareExternalUrl('')).toEqual('/app');
locationStrategy.pushState(null, 'Title', '', '');
expect(platformLocation.spy('pushState')).toHaveBeenCalledWith(null, 'Title', '/app');
});
});
describe('with APP_BASE_HREF with both leading and trailing slash', () => {
beforeEachProviders(() => [provide(APP_BASE_HREF, {useValue: '/app/'})]);
beforeEach(inject([PlatformLocation, PathLocationStrategy], (pl, ls) => {
platformLocation = pl;
locationStrategy = ls;
platformLocation.spy('pushState');
platformLocation.pathname = '';
}));
it('should prepend urls with a hash for non-empty URLs', () => {
expect(locationStrategy.prepareExternalUrl('foo')).toEqual('/app/foo');
locationStrategy.pushState(null, 'Title', 'foo', '');
expect(platformLocation.spy('pushState')).toHaveBeenCalledWith(null, 'Title', '/app/foo');
});
it('should prepend urls with a hash for URLs with query params', () => {
expect(locationStrategy.prepareExternalUrl('foo?bar')).toEqual('/app/foo?bar');
locationStrategy.pushState(null, 'Title', 'foo', 'bar=baz');
expect(platformLocation.spy('pushState'))
.toHaveBeenCalledWith(null, 'Title', '/app/foo?bar=baz');
});
it('should not prepend a hash to external urls for an empty internal URL', () => {
expect(locationStrategy.prepareExternalUrl('')).toEqual('/app/');
locationStrategy.pushState(null, 'Title', '', '');
expect(platformLocation.spy('pushState')).toHaveBeenCalledWith(null, 'Title', '/app/');
});
});
});
}
function makeSpyPlatformLocation() {
var platformLocation = new SpyPlatformLocation();
platformLocation.spy('getBaseHrefFromDOM').andReturn('');
platformLocation.spy('pushState');
platformLocation.pathname = '';
return platformLocation;
}
+5
View File
@@ -17,3 +17,8 @@ class SpyRouter extends SpyObject implements Router {
class SpyRouterOutlet extends SpyObject implements RouterOutlet {
noSuchMethod(m) => super.noSuchMethod(m);
}
class SpyPlatformLocation extends SpyObject implements PlatformLocation {
String pathname;
noSuchMethod(m) => super.noSuchMethod(m);
}
+7 -2
View File
@@ -1,4 +1,4 @@
import {Router, RouterOutlet, Location} from 'angular2/router';
import {Router, RouterOutlet, Location, PlatformLocation} from 'angular2/router';
import {SpyObject, proxy} from 'angular2/testing_internal';
export class SpyRouter extends SpyObject {
@@ -11,4 +11,9 @@ export class SpyRouterOutlet extends SpyObject {
export class SpyLocation extends SpyObject {
constructor() { super(Location); }
}
}
export class SpyPlatformLocation extends SpyObject {
pathname: string = null;
constructor() { super(SpyPlatformLocation); }
}