2016-07-21 20:12:00 -04:00
|
|
|
/**
|
|
|
|
* @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
|
|
|
|
*/
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
|
|
|
|
|
|
|
|
import {createUrlTree} from '../src/create_url_tree';
|
2016-06-02 17:44:57 -04:00
|
|
|
import {ActivatedRoute, ActivatedRouteSnapshot, advanceActivatedRoute} from '../src/router_state';
|
2016-05-26 19:51:19 -04:00
|
|
|
import {PRIMARY_OUTLET, Params} from '../src/shared';
|
2016-09-27 20:12:25 -04:00
|
|
|
import {DefaultUrlSerializer, UrlSegmentGroup, UrlTree} from '../src/url_tree';
|
2016-05-26 19:51:19 -04:00
|
|
|
|
2016-08-04 21:56:22 -04:00
|
|
|
describe('createUrlTree', () => {
|
2016-05-26 19:51:19 -04:00
|
|
|
const serializer = new DefaultUrlSerializer();
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should navigate to the root', () => {
|
|
|
|
const p = serializer.parse('/');
|
|
|
|
const t = createRoot(p, ['/']);
|
|
|
|
expect(serializer.serialize(t)).toEqual('/');
|
2016-05-26 19:51:19 -04:00
|
|
|
});
|
|
|
|
|
2016-07-08 13:56:36 -04:00
|
|
|
it('should error when navigating to the root segment with params', () => {
|
|
|
|
const p = serializer.parse('/');
|
|
|
|
expect(() => createRoot(p, ['/', {p: 11}]))
|
|
|
|
.toThrowError(/Root segment cannot have matrix parameters/);
|
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should support nested segments', () => {
|
|
|
|
const p = serializer.parse('/a/b');
|
|
|
|
const t = createRoot(p, ['/one', 11, 'two', 22]);
|
|
|
|
expect(serializer.serialize(t)).toEqual('/one/11/two/22');
|
2016-05-26 19:51:19 -04:00
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should stringify positional parameters', () => {
|
|
|
|
const p = serializer.parse('/a/b');
|
|
|
|
const t = createRoot(p, ['/one', 11]);
|
2016-07-25 15:15:07 -04:00
|
|
|
const params = t.root.children[PRIMARY_OUTLET].segments;
|
2016-06-21 14:49:42 -04:00
|
|
|
expect(params[0].path).toEqual('one');
|
|
|
|
expect(params[1].path).toEqual('11');
|
2016-06-16 17:45:16 -04:00
|
|
|
});
|
|
|
|
|
2016-08-04 20:19:23 -04:00
|
|
|
it('should support first segments contaings slashes', () => {
|
|
|
|
const p = serializer.parse('/');
|
|
|
|
const t = createRoot(p, [{segmentPath: '/one'}, 'two/three']);
|
|
|
|
expect(serializer.serialize(t)).toEqual('/%2Fone/two%2Fthree');
|
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should preserve secondary segments', () => {
|
|
|
|
const p = serializer.parse('/a/11/b(right:c)');
|
|
|
|
const t = createRoot(p, ['/a', 11, 'd']);
|
|
|
|
expect(serializer.serialize(t)).toEqual('/a/11/d(right:c)');
|
2016-05-26 19:51:19 -04:00
|
|
|
});
|
|
|
|
|
2016-08-07 21:34:12 -04:00
|
|
|
it('should support updating secondary segments (absolute)', () => {
|
|
|
|
const p = serializer.parse('/a(right:b)');
|
|
|
|
const t = createRoot(p, ['/', {outlets: {right: ['c']}}]);
|
|
|
|
expect(serializer.serialize(t)).toEqual('/a(right:c)');
|
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should support updating secondary segments', () => {
|
|
|
|
const p = serializer.parse('/a(right:b)');
|
2016-07-12 12:49:55 -04:00
|
|
|
const t = createRoot(p, [{outlets: {right: ['c', 11, 'd']}}]);
|
2016-06-21 14:49:42 -04:00
|
|
|
expect(serializer.serialize(t)).toEqual('/a(right:c/11/d)');
|
2016-06-06 21:27:36 -04:00
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should support updating secondary segments (nested case)', () => {
|
|
|
|
const p = serializer.parse('/a/(b//right:c)');
|
2016-07-12 12:49:55 -04:00
|
|
|
const t = createRoot(p, ['a', {outlets: {right: ['d', 11, 'e']}}]);
|
2016-06-21 14:49:42 -04:00
|
|
|
expect(serializer.serialize(t)).toEqual('/a/(b//right:d/11/e)');
|
2016-06-06 21:27:36 -04:00
|
|
|
});
|
2016-06-21 14:49:42 -04:00
|
|
|
|
2016-08-07 22:04:57 -04:00
|
|
|
it('should throw when outlets is not the last command', () => {
|
|
|
|
const p = serializer.parse('/a');
|
|
|
|
expect(() => createRoot(p, ['a', {outlets: {right: ['c']}}, 'c']))
|
|
|
|
.toThrowError('{outlets:{}} has to be the last command');
|
|
|
|
});
|
|
|
|
|
2016-07-12 12:49:55 -04:00
|
|
|
it('should support updating using a string', () => {
|
|
|
|
const p = serializer.parse('/a(right:b)');
|
|
|
|
const t = createRoot(p, [{outlets: {right: 'c/11/d'}}]);
|
|
|
|
expect(serializer.serialize(t)).toEqual('/a(right:c/11/d)');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should support updating primary and secondary segments at once', () => {
|
|
|
|
const p = serializer.parse('/a(right:b)');
|
2016-07-22 16:25:48 -04:00
|
|
|
const t = createRoot(p, [{outlets: {primary: 'y/z', right: 'c/11/d'}}]);
|
2016-07-12 12:49:55 -04:00
|
|
|
expect(serializer.serialize(t)).toEqual('/y/z(right:c/11/d)');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should support removing primary segment', () => {
|
|
|
|
const p = serializer.parse('/a/(b//right:c)');
|
2016-07-22 16:25:48 -04:00
|
|
|
const t = createRoot(p, ['a', {outlets: {primary: null, right: 'd'}}]);
|
2016-07-12 12:49:55 -04:00
|
|
|
expect(serializer.serialize(t)).toEqual('/a/(right:d)');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should support removing secondary segments', () => {
|
|
|
|
const p = serializer.parse('/a(right:b)');
|
|
|
|
const t = createRoot(p, [{outlets: {right: null}}]);
|
|
|
|
expect(serializer.serialize(t)).toEqual('/a');
|
|
|
|
});
|
|
|
|
|
2016-05-26 19:51:19 -04:00
|
|
|
it('should update matrix parameters', () => {
|
2016-06-21 14:49:42 -04:00
|
|
|
const p = serializer.parse('/a;pp=11');
|
|
|
|
const t = createRoot(p, ['/a', {pp: 22, dd: 33}]);
|
|
|
|
expect(serializer.serialize(t)).toEqual('/a;pp=22;dd=33');
|
2016-05-26 19:51:19 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should create matrix parameters', () => {
|
2016-06-21 14:49:42 -04:00
|
|
|
const p = serializer.parse('/a');
|
|
|
|
const t = createRoot(p, ['/a', {pp: 22, dd: 33}]);
|
|
|
|
expect(serializer.serialize(t)).toEqual('/a;pp=22;dd=33');
|
2016-05-26 19:51:19 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should create matrix parameters together with other segments', () => {
|
2016-06-21 14:49:42 -04:00
|
|
|
const p = serializer.parse('/a');
|
2016-08-04 20:19:23 -04:00
|
|
|
const t = createRoot(p, ['/a', 'b', {aa: 22, bb: 33}]);
|
2016-06-21 14:49:42 -04:00
|
|
|
expect(serializer.serialize(t)).toEqual('/a/b;aa=22;bb=33');
|
2016-05-26 19:51:19 -04:00
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
describe('relative navigation', () => {
|
|
|
|
it('should work', () => {
|
|
|
|
const p = serializer.parse('/a/(c//left:cp)(left:ap)');
|
|
|
|
const t = create(p.root.children[PRIMARY_OUTLET], 0, p, ['c2']);
|
|
|
|
expect(serializer.serialize(t)).toEqual('/a/(c2//left:cp)(left:ap)');
|
2016-05-26 19:51:19 -04:00
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should work when the first command starts with a ./', () => {
|
|
|
|
const p = serializer.parse('/a/(c//left:cp)(left:ap)');
|
|
|
|
const t = create(p.root.children[PRIMARY_OUTLET], 0, p, ['./c2']);
|
|
|
|
expect(serializer.serialize(t)).toEqual('/a/(c2//left:cp)(left:ap)');
|
2016-05-26 19:51:19 -04:00
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should work when the first command is ./)', () => {
|
|
|
|
const p = serializer.parse('/a/(c//left:cp)(left:ap)');
|
|
|
|
const t = create(p.root.children[PRIMARY_OUTLET], 0, p, ['./', 'c2']);
|
|
|
|
expect(serializer.serialize(t)).toEqual('/a/(c2//left:cp)(left:ap)');
|
2016-05-26 19:51:19 -04:00
|
|
|
});
|
|
|
|
|
2016-08-09 20:03:17 -04:00
|
|
|
it('should support parameters-only navigation', () => {
|
|
|
|
const p = serializer.parse('/a');
|
|
|
|
const t = create(p.root.children[PRIMARY_OUTLET], 0, p, [{k: 99}]);
|
|
|
|
expect(serializer.serialize(t)).toEqual('/a;k=99');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should support parameters-only navigation (nested case)', () => {
|
2016-06-21 14:49:42 -04:00
|
|
|
const p = serializer.parse('/a/(c//left:cp)(left:ap)');
|
2016-06-14 17:55:59 -04:00
|
|
|
const t = create(p.root.children[PRIMARY_OUTLET], 0, p, [{'x': 99}]);
|
2016-08-09 20:03:17 -04:00
|
|
|
expect(serializer.serialize(t)).toEqual('/a;x=99(left:ap)');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should support parameters-only navigation (with a double dot)', () => {
|
|
|
|
const p = serializer.parse('/a/(c//left:cp)(left:ap)');
|
|
|
|
const t =
|
|
|
|
create(p.root.children[PRIMARY_OUTLET].children[PRIMARY_OUTLET], 0, p, ['../', {x: 5}]);
|
|
|
|
expect(serializer.serialize(t)).toEqual('/a;x=5(left:ap)');
|
2016-05-26 19:51:19 -04:00
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should work when index > 0', () => {
|
|
|
|
const p = serializer.parse('/a/c');
|
|
|
|
const t = create(p.root.children[PRIMARY_OUTLET], 1, p, ['c2']);
|
|
|
|
expect(serializer.serialize(t)).toEqual('/a/c/c2');
|
2016-05-26 19:51:19 -04:00
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should support going to a parent (within a segment)', () => {
|
|
|
|
const p = serializer.parse('/a/c');
|
|
|
|
const t = create(p.root.children[PRIMARY_OUTLET], 1, p, ['../c2']);
|
|
|
|
expect(serializer.serialize(t)).toEqual('/a/c2');
|
2016-05-26 19:51:19 -04:00
|
|
|
});
|
|
|
|
|
2016-08-09 20:03:17 -04:00
|
|
|
it('should support going to a parent (across segments)', () => {
|
2016-06-21 14:49:42 -04:00
|
|
|
const p = serializer.parse('/q/(a/(c//left:cp)//left:qp)(left:ap)');
|
2016-06-14 17:55:59 -04:00
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
const t =
|
|
|
|
create(p.root.children[PRIMARY_OUTLET].children[PRIMARY_OUTLET], 0, p, ['../../q2']);
|
|
|
|
expect(serializer.serialize(t)).toEqual('/q2(left:ap)');
|
2016-06-14 17:55:59 -04:00
|
|
|
});
|
|
|
|
|
2016-07-18 17:53:13 -04:00
|
|
|
it('should navigate to the root', () => {
|
2016-06-21 14:49:42 -04:00
|
|
|
const p = serializer.parse('/a/c');
|
2016-06-14 17:55:59 -04:00
|
|
|
const t = create(p.root.children[PRIMARY_OUTLET], 0, p, ['../']);
|
2016-07-18 17:53:13 -04:00
|
|
|
expect(serializer.serialize(t)).toEqual('/');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should work with ../ when absolute url', () => {
|
|
|
|
const p = serializer.parse('/a/c');
|
|
|
|
const t = create(p.root.children[PRIMARY_OUTLET], 1, p, ['../', 'c2']);
|
|
|
|
expect(serializer.serialize(t)).toEqual('/a/c2');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should work with position = -1', () => {
|
|
|
|
const p = serializer.parse('/');
|
|
|
|
const t = create(p.root, -1, p, ['11']);
|
|
|
|
expect(serializer.serialize(t)).toEqual('/11');
|
2016-06-14 17:55:59 -04:00
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should throw when too many ..', () => {
|
|
|
|
const p = serializer.parse('/a/(c//left:cp)(left:ap)');
|
|
|
|
expect(() => create(p.root.children[PRIMARY_OUTLET], 0, p, ['../../']))
|
|
|
|
.toThrowError('Invalid number of \'../\'');
|
2016-05-26 19:51:19 -04:00
|
|
|
});
|
2016-08-07 22:04:57 -04:00
|
|
|
|
|
|
|
it('should support updating secondary segments', () => {
|
|
|
|
const p = serializer.parse('/a/b');
|
|
|
|
const t = create(p.root.children[PRIMARY_OUTLET], 1, p, [{outlets: {right: ['c']}}]);
|
|
|
|
expect(serializer.serialize(t)).toEqual('/a/b/(right:c)');
|
|
|
|
});
|
2016-05-26 19:51:19 -04:00
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should set query params', () => {
|
|
|
|
const p = serializer.parse('/');
|
2016-06-14 17:55:59 -04:00
|
|
|
const t = createRoot(p, [], {a: 'hey'});
|
2016-06-06 19:34:48 -04:00
|
|
|
expect(t.queryParams).toEqual({a: 'hey'});
|
2016-05-26 19:51:19 -04:00
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should stringify query params', () => {
|
|
|
|
const p = serializer.parse('/');
|
2016-06-14 17:55:59 -04:00
|
|
|
const t = createRoot(p, [], <any>{a: 1});
|
2016-06-06 19:34:48 -04:00
|
|
|
expect(t.queryParams).toEqual({a: '1'});
|
2016-05-26 19:51:19 -04:00
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should set fragment', () => {
|
|
|
|
const p = serializer.parse('/');
|
|
|
|
const t = createRoot(p, [], {}, 'fragment');
|
|
|
|
expect(t.fragment).toEqual('fragment');
|
2016-05-26 19:51:19 -04:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-06-14 17:55:59 -04:00
|
|
|
function createRoot(tree: UrlTree, commands: any[], queryParams?: Params, fragment?: string) {
|
2016-06-27 17:00:07 -04:00
|
|
|
const s = new ActivatedRouteSnapshot(
|
2016-08-02 18:31:56 -04:00
|
|
|
[], <any>{}, <any>{}, '', <any>{}, PRIMARY_OUTLET, 'someComponent', null, tree.root, -1,
|
|
|
|
<any>null);
|
2016-06-21 14:49:42 -04:00
|
|
|
const a = new ActivatedRoute(
|
2016-06-27 17:00:07 -04:00
|
|
|
new BehaviorSubject(null), new BehaviorSubject(null), new BehaviorSubject(null),
|
2016-08-02 18:31:56 -04:00
|
|
|
new BehaviorSubject(null), new BehaviorSubject(null), PRIMARY_OUTLET, 'someComponent', s);
|
2016-06-14 17:55:59 -04:00
|
|
|
advanceActivatedRoute(a);
|
|
|
|
return createUrlTree(a, tree, commands, queryParams, fragment);
|
|
|
|
}
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
function create(
|
2016-07-25 15:15:07 -04:00
|
|
|
segment: UrlSegmentGroup, startIndex: number, tree: UrlTree, commands: any[],
|
|
|
|
queryParams?: Params, fragment?: string) {
|
2016-06-14 17:55:59 -04:00
|
|
|
if (!segment) {
|
|
|
|
expect(segment).toBeDefined();
|
2016-05-26 19:51:19 -04:00
|
|
|
}
|
2016-06-21 14:49:42 -04:00
|
|
|
const s = new ActivatedRouteSnapshot(
|
2016-08-02 18:31:56 -04:00
|
|
|
[], <any>{}, <any>{}, '', <any>{}, PRIMARY_OUTLET, 'someComponent', null, <any>segment,
|
|
|
|
startIndex, <any>null);
|
2016-06-21 14:49:42 -04:00
|
|
|
const a = new ActivatedRoute(
|
2016-06-27 17:00:07 -04:00
|
|
|
new BehaviorSubject(null), new BehaviorSubject(null), new BehaviorSubject(null),
|
2016-08-02 18:31:56 -04:00
|
|
|
new BehaviorSubject(null), new BehaviorSubject(null), PRIMARY_OUTLET, 'someComponent', s);
|
2016-06-02 17:44:57 -04:00
|
|
|
advanceActivatedRoute(a);
|
2016-06-06 19:34:48 -04:00
|
|
|
return createUrlTree(a, tree, commands, queryParams, fragment);
|
2016-05-26 19:51:19 -04:00
|
|
|
}
|