2016-07-21 20:12:00 -04:00
|
|
|
/**
|
|
|
|
* @license
|
2020-05-19 15:08:49 -04:00
|
|
|
* Copyright Google LLC All Rights Reserved.
|
2016-07-21 20:12:00 -04:00
|
|
|
*
|
|
|
|
* 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 {PRIMARY_OUTLET} from '../src/shared';
|
2020-04-13 19:40:21 -04:00
|
|
|
import {DefaultUrlSerializer, encodeUriFragment, encodeUriQuery, encodeUriSegment, serializePath, UrlSegmentGroup} from '../src/url_tree';
|
2016-05-21 20:35:55 -04:00
|
|
|
|
|
|
|
describe('url serializer', () => {
|
2016-05-26 19:50:59 -04:00
|
|
|
const url = new DefaultUrlSerializer();
|
2016-05-21 20:35:55 -04:00
|
|
|
|
|
|
|
it('should parse the root url', () => {
|
2016-06-21 14:49:42 -04:00
|
|
|
const tree = url.parse('/');
|
|
|
|
expectSegment(tree.root, '');
|
|
|
|
expect(url.serialize(tree)).toEqual('/');
|
2016-05-21 20:35:55 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should parse non-empty urls', () => {
|
2016-06-21 14:49:42 -04:00
|
|
|
const tree = url.parse('one/two');
|
|
|
|
expectSegment(tree.root.children[PRIMARY_OUTLET], 'one/two');
|
|
|
|
expect(url.serialize(tree)).toEqual('/one/two');
|
2016-05-21 20:35:55 -04:00
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should parse multiple secondary segments', () => {
|
|
|
|
const tree = url.parse('/one/two(left:three//right:four)');
|
2016-06-14 17:55:59 -04:00
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
expectSegment(tree.root.children[PRIMARY_OUTLET], 'one/two');
|
|
|
|
expectSegment(tree.root.children['left'], 'three');
|
|
|
|
expectSegment(tree.root.children['right'], 'four');
|
2016-06-14 17:55:59 -04:00
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
expect(url.serialize(tree)).toEqual('/one/two(left:three//right:four)');
|
2016-06-14 17:55:59 -04:00
|
|
|
});
|
|
|
|
|
2016-07-21 17:50:38 -04:00
|
|
|
it('should parse top-level nodes with only secondary segment', () => {
|
|
|
|
const tree = url.parse('/(left:one)');
|
|
|
|
|
|
|
|
expect(tree.root.numberOfChildren).toEqual(1);
|
|
|
|
expectSegment(tree.root.children['left'], 'one');
|
|
|
|
|
|
|
|
expect(url.serialize(tree)).toEqual('/(left:one)');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should parse nodes with only secondary segment', () => {
|
|
|
|
const tree = url.parse('/one/(left:two)');
|
|
|
|
|
|
|
|
const one = tree.root.children[PRIMARY_OUTLET];
|
|
|
|
expectSegment(one, 'one', true);
|
|
|
|
expect(one.numberOfChildren).toEqual(1);
|
|
|
|
expectSegment(one.children['left'], 'two');
|
|
|
|
|
|
|
|
expect(url.serialize(tree)).toEqual('/one/(left:two)');
|
|
|
|
});
|
|
|
|
|
2016-06-24 14:17:17 -04:00
|
|
|
it('should not parse empty path segments with params', () => {
|
|
|
|
expect(() => url.parse('/one/two/(;a=1//right:;b=2)'))
|
|
|
|
.toThrowError(/Empty path url segment cannot have parameters/);
|
2016-06-19 16:45:40 -04:00
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should parse scoped secondary segments', () => {
|
|
|
|
const tree = url.parse('/one/(two//left:three)');
|
2016-05-21 20:35:55 -04:00
|
|
|
|
2016-06-14 17:55:59 -04:00
|
|
|
const primary = tree.root.children[PRIMARY_OUTLET];
|
2016-06-21 14:49:42 -04:00
|
|
|
expectSegment(primary, 'one', true);
|
2016-05-21 20:35:55 -04:00
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
expectSegment(primary.children[PRIMARY_OUTLET], 'two');
|
|
|
|
expectSegment(primary.children['left'], 'three');
|
2016-05-21 20:35:55 -04:00
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
expect(url.serialize(tree)).toEqual('/one/(two//left:three)');
|
2016-05-21 20:35:55 -04:00
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should parse scoped secondary segments with unscoped ones', () => {
|
|
|
|
const tree = url.parse('/one/(two//left:three)(right:four)');
|
2016-05-21 20:35:55 -04:00
|
|
|
|
2016-06-14 17:55:59 -04:00
|
|
|
const primary = tree.root.children[PRIMARY_OUTLET];
|
2016-06-21 14:49:42 -04:00
|
|
|
expectSegment(primary, 'one', true);
|
|
|
|
expectSegment(primary.children[PRIMARY_OUTLET], 'two');
|
|
|
|
expectSegment(primary.children['left'], 'three');
|
|
|
|
expectSegment(tree.root.children['right'], 'four');
|
2016-05-21 20:35:55 -04:00
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
expect(url.serialize(tree)).toEqual('/one/(two//left:three)(right:four)');
|
2016-05-21 20:35:55 -04:00
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should parse secondary segments that have children', () => {
|
|
|
|
const tree = url.parse('/one(left:two/three)');
|
2016-05-21 20:35:55 -04:00
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
expectSegment(tree.root.children[PRIMARY_OUTLET], 'one');
|
|
|
|
expectSegment(tree.root.children['left'], 'two/three');
|
2016-05-21 20:35:55 -04:00
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
expect(url.serialize(tree)).toEqual('/one(left:two/three)');
|
2016-05-21 20:35:55 -04:00
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should parse an empty secondary segment group', () => {
|
|
|
|
const tree = url.parse('/one()');
|
2016-05-21 20:35:55 -04:00
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
expectSegment(tree.root.children[PRIMARY_OUTLET], 'one');
|
2016-05-21 20:35:55 -04:00
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
expect(url.serialize(tree)).toEqual('/one');
|
2016-05-21 20:35:55 -04:00
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should parse key-value matrix params', () => {
|
|
|
|
const tree = url.parse('/one;a=11a;b=11b(left:two;c=22//right:three;d=33)');
|
2016-05-21 20:35:55 -04:00
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
expectSegment(tree.root.children[PRIMARY_OUTLET], 'one;a=11a;b=11b');
|
|
|
|
expectSegment(tree.root.children['left'], 'two;c=22');
|
|
|
|
expectSegment(tree.root.children['right'], 'three;d=33');
|
2016-05-21 20:35:55 -04:00
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
expect(url.serialize(tree)).toEqual('/one;a=11a;b=11b(left:two;c=22//right:three;d=33)');
|
2016-05-21 20:35:55 -04:00
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should parse key only matrix params', () => {
|
|
|
|
const tree = url.parse('/one;a');
|
2016-05-21 20:35:55 -04:00
|
|
|
|
2016-08-26 18:41:32 -04:00
|
|
|
expectSegment(tree.root.children[PRIMARY_OUTLET], 'one;a=');
|
2016-05-21 20:35:55 -04:00
|
|
|
|
2016-08-26 18:41:32 -04:00
|
|
|
expect(url.serialize(tree)).toEqual('/one;a=');
|
2016-05-21 20:35:55 -04:00
|
|
|
});
|
|
|
|
|
2016-06-25 15:07:47 -04:00
|
|
|
it('should parse query params (root)', () => {
|
|
|
|
const tree = url.parse('/?a=1&b=2');
|
|
|
|
expect(tree.root.children).toEqual({});
|
|
|
|
expect(tree.queryParams).toEqual({a: '1', b: '2'});
|
|
|
|
expect(url.serialize(tree)).toEqual('/?a=1&b=2');
|
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should parse query params', () => {
|
|
|
|
const tree = url.parse('/one?a=1&b=2');
|
2016-06-06 19:34:48 -04:00
|
|
|
expect(tree.queryParams).toEqual({a: '1', b: '2'});
|
2016-05-21 20:35:55 -04:00
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should parse query params when with parenthesis', () => {
|
|
|
|
const tree = url.parse('/one?a=(11)&b=(22)');
|
2016-06-16 19:28:35 -04:00
|
|
|
expect(tree.queryParams).toEqual({a: '(11)', b: '(22)'});
|
|
|
|
});
|
|
|
|
|
2016-06-24 14:48:52 -04:00
|
|
|
it('should parse query params when with slashes', () => {
|
|
|
|
const tree = url.parse('/one?a=1/2&b=3/4');
|
|
|
|
expect(tree.queryParams).toEqual({a: '1/2', b: '3/4'});
|
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should parse key only query params', () => {
|
|
|
|
const tree = url.parse('/one?a');
|
2016-07-30 17:34:03 -04:00
|
|
|
expect(tree.queryParams).toEqual({a: ''});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should parse a value-empty query param', () => {
|
|
|
|
const tree = url.parse('/one?a=');
|
|
|
|
expect(tree.queryParams).toEqual({a: ''});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should parse value-empty query params', () => {
|
|
|
|
const tree = url.parse('/one?a=&b=');
|
|
|
|
expect(tree.queryParams).toEqual({a: '', b: ''});
|
2016-05-21 20:35:55 -04:00
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should serializer query params', () => {
|
|
|
|
const tree = url.parse('/one?a');
|
2016-07-30 17:34:03 -04:00
|
|
|
expect(url.serialize(tree)).toEqual('/one?a=');
|
2016-05-21 20:35:55 -04:00
|
|
|
});
|
|
|
|
|
2016-09-06 07:39:53 -04:00
|
|
|
it('should handle multiple query params of the same name into an array', () => {
|
|
|
|
const tree = url.parse('/one?a=foo&a=bar&a=swaz');
|
|
|
|
expect(tree.queryParams).toEqual({a: ['foo', 'bar', 'swaz']});
|
2017-03-17 13:09:42 -04:00
|
|
|
expect(tree.queryParamMap.get('a')).toEqual('foo');
|
|
|
|
expect(tree.queryParamMap.getAll('a')).toEqual(['foo', 'bar', 'swaz']);
|
2017-03-15 18:27:19 -04:00
|
|
|
expect(url.serialize(tree)).toEqual('/one?a=foo&a=bar&a=swaz');
|
2016-09-06 07:39:53 -04:00
|
|
|
});
|
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should parse fragment', () => {
|
|
|
|
const tree = url.parse('/one#two');
|
|
|
|
expect(tree.fragment).toEqual('two');
|
|
|
|
expect(url.serialize(tree)).toEqual('/one#two');
|
2016-05-21 20:35:55 -04:00
|
|
|
});
|
|
|
|
|
2016-07-22 19:56:10 -04:00
|
|
|
it('should parse fragment (root)', () => {
|
|
|
|
const tree = url.parse('/#one');
|
|
|
|
expectSegment(tree.root, '');
|
|
|
|
expect(url.serialize(tree)).toEqual('/#one');
|
|
|
|
});
|
2016-07-21 18:58:21 -04:00
|
|
|
|
2016-06-21 14:49:42 -04:00
|
|
|
it('should parse empty fragment', () => {
|
|
|
|
const tree = url.parse('/one#');
|
|
|
|
expect(tree.fragment).toEqual('');
|
|
|
|
expect(url.serialize(tree)).toEqual('/one#');
|
2016-05-21 20:35:55 -04:00
|
|
|
});
|
2016-07-07 19:57:25 -04:00
|
|
|
|
|
|
|
describe('encoding/decoding', () => {
|
|
|
|
it('should encode/decode path segments and parameters', () => {
|
2020-04-13 19:40:21 -04:00
|
|
|
const u = `/${encodeUriSegment('one two')};${encodeUriSegment('p 1')}=${
|
|
|
|
encodeUriSegment('v 1')};${encodeUriSegment('p 2')}=${encodeUriSegment('v 2')}`;
|
2016-07-07 19:57:25 -04:00
|
|
|
const tree = url.parse(u);
|
|
|
|
|
2016-07-25 15:15:07 -04:00
|
|
|
expect(tree.root.children[PRIMARY_OUTLET].segments[0].path).toEqual('one two');
|
|
|
|
expect(tree.root.children[PRIMARY_OUTLET].segments[0].parameters)
|
2016-07-07 19:57:25 -04:00
|
|
|
.toEqual({['p 1']: 'v 1', ['p 2']: 'v 2'});
|
|
|
|
expect(url.serialize(tree)).toEqual(u);
|
|
|
|
});
|
|
|
|
|
2016-08-04 20:19:23 -04:00
|
|
|
it('should encode/decode "slash" in path segments and parameters', () => {
|
2020-04-13 19:40:21 -04:00
|
|
|
const u = `/${encodeUriSegment('one/two')};${encodeUriSegment('p/1')}=${
|
|
|
|
encodeUriSegment('v/1')}/three`;
|
2016-08-04 20:19:23 -04:00
|
|
|
const tree = url.parse(u);
|
2017-03-17 13:09:42 -04:00
|
|
|
const segment = tree.root.children[PRIMARY_OUTLET].segments[0];
|
|
|
|
expect(segment.path).toEqual('one/two');
|
|
|
|
expect(segment.parameters).toEqual({'p/1': 'v/1'});
|
|
|
|
expect(segment.parameterMap.get('p/1')).toEqual('v/1');
|
|
|
|
expect(segment.parameterMap.getAll('p/1')).toEqual(['v/1']);
|
2016-08-04 20:19:23 -04:00
|
|
|
expect(url.serialize(tree)).toEqual(u);
|
|
|
|
});
|
|
|
|
|
2016-07-07 19:57:25 -04:00
|
|
|
it('should encode/decode query params', () => {
|
2020-04-13 19:40:21 -04:00
|
|
|
const u = `/one?${encodeUriQuery('p 1')}=${encodeUriQuery('v 1')}&${encodeUriQuery('p 2')}=${
|
|
|
|
encodeUriQuery('v 2')}`;
|
2016-07-07 19:57:25 -04:00
|
|
|
const tree = url.parse(u);
|
|
|
|
|
2017-03-17 13:09:42 -04:00
|
|
|
expect(tree.queryParams).toEqual({'p 1': 'v 1', 'p 2': 'v 2'});
|
|
|
|
expect(tree.queryParamMap.get('p 1')).toEqual('v 1');
|
|
|
|
expect(tree.queryParamMap.get('p 2')).toEqual('v 2');
|
2016-07-07 19:57:25 -04:00
|
|
|
expect(url.serialize(tree)).toEqual(u);
|
|
|
|
});
|
|
|
|
|
2018-02-20 18:08:41 -05:00
|
|
|
it('should decode spaces in query as %20 or +', () => {
|
|
|
|
const u1 = `/one?foo=bar baz`;
|
|
|
|
const u2 = `/one?foo=bar+baz`;
|
|
|
|
const u3 = `/one?foo=bar%20baz`;
|
|
|
|
|
|
|
|
const u1p = url.parse(u1);
|
|
|
|
const u2p = url.parse(u2);
|
|
|
|
const u3p = url.parse(u3);
|
|
|
|
|
|
|
|
expect(url.serialize(u1p)).toBe(url.serialize(u2p));
|
|
|
|
expect(url.serialize(u2p)).toBe(url.serialize(u3p));
|
|
|
|
expect(u1p.queryParamMap.get('foo')).toBe('bar baz');
|
|
|
|
expect(u2p.queryParamMap.get('foo')).toBe('bar baz');
|
|
|
|
expect(u3p.queryParamMap.get('foo')).toBe('bar baz');
|
|
|
|
});
|
|
|
|
|
2017-07-06 20:10:25 -04:00
|
|
|
it('should encode query params leaving sub-delimiters intact', () => {
|
2018-02-20 18:08:41 -05:00
|
|
|
const percentChars = '/?#&+=[] ';
|
|
|
|
const percentCharsEncoded = '%2F%3F%23%26%2B%3D%5B%5D%20';
|
2018-02-23 21:12:40 -05:00
|
|
|
const intactChars = '!$\'()*,;:';
|
2017-07-06 20:10:25 -04:00
|
|
|
const params = percentChars + intactChars;
|
|
|
|
const paramsEncoded = percentCharsEncoded + intactChars;
|
|
|
|
const mixedCaseString = 'sTrInG';
|
|
|
|
|
2018-02-20 18:08:41 -05:00
|
|
|
expect(percentCharsEncoded).toEqual(encodeUriQuery(percentChars));
|
|
|
|
expect(intactChars).toEqual(encodeUriQuery(intactChars));
|
2017-07-06 20:10:25 -04:00
|
|
|
// Verify it replaces repeated characters correctly
|
2018-02-20 18:08:41 -05:00
|
|
|
expect(paramsEncoded + paramsEncoded).toEqual(encodeUriQuery(params + params));
|
2017-07-06 20:10:25 -04:00
|
|
|
// Verify it doesn't change the case of alpha characters
|
2018-02-20 18:08:41 -05:00
|
|
|
expect(mixedCaseString + paramsEncoded).toEqual(encodeUriQuery(mixedCaseString + params));
|
2017-07-06 20:10:25 -04:00
|
|
|
});
|
|
|
|
|
2016-07-07 19:57:25 -04:00
|
|
|
it('should encode/decode fragment', () => {
|
2018-03-09 14:18:45 -05:00
|
|
|
const u = `/one#${encodeUriFragment('one two=three four')}`;
|
2016-07-07 19:57:25 -04:00
|
|
|
const tree = url.parse(u);
|
|
|
|
|
2016-08-25 09:08:07 -04:00
|
|
|
expect(tree.fragment).toEqual('one two=three four');
|
2018-03-09 14:18:45 -05:00
|
|
|
expect(url.serialize(tree)).toEqual('/one#one%20two=three%20four');
|
2018-02-20 18:08:41 -05:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('special character encoding/decoding', () => {
|
|
|
|
// Tests specific to https://github.com/angular/angular/issues/10280
|
|
|
|
it('should parse encoded parens in matrix params', () => {
|
|
|
|
const auxRoutesUrl = '/abc;foo=(other:val)';
|
|
|
|
const fooValueUrl = '/abc;foo=%28other:val%29';
|
|
|
|
|
|
|
|
const auxParsed = url.parse(auxRoutesUrl).root;
|
|
|
|
const fooParsed = url.parse(fooValueUrl).root;
|
|
|
|
|
|
|
|
|
|
|
|
// Test base case
|
|
|
|
expect(auxParsed.children[PRIMARY_OUTLET].segments.length).toBe(1);
|
|
|
|
expect(auxParsed.children[PRIMARY_OUTLET].segments[0].path).toBe('abc');
|
|
|
|
expect(auxParsed.children[PRIMARY_OUTLET].segments[0].parameters).toEqual({foo: ''});
|
|
|
|
expect(auxParsed.children['other'].segments.length).toBe(1);
|
|
|
|
expect(auxParsed.children['other'].segments[0].path).toBe('val');
|
|
|
|
|
|
|
|
// Confirm matrix params are URL decoded
|
|
|
|
expect(fooParsed.children[PRIMARY_OUTLET].segments.length).toBe(1);
|
|
|
|
expect(fooParsed.children[PRIMARY_OUTLET].segments[0].path).toBe('abc');
|
|
|
|
expect(fooParsed.children[PRIMARY_OUTLET].segments[0].parameters).toEqual({
|
|
|
|
foo: '(other:val)'
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should serialize encoded parens in matrix params', () => {
|
|
|
|
const testUrl = '/abc;foo=%28one%29';
|
|
|
|
|
|
|
|
const parsed = url.parse(testUrl);
|
|
|
|
|
|
|
|
expect(url.serialize(parsed)).toBe('/abc;foo=%28one%29');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should not serialize encoded parens in query params', () => {
|
|
|
|
const testUrl = '/abc?foo=%28one%29';
|
|
|
|
|
|
|
|
const parsed = url.parse(testUrl);
|
|
|
|
|
|
|
|
expect(parsed.queryParams).toEqual({foo: '(one)'});
|
|
|
|
|
|
|
|
expect(url.serialize(parsed)).toBe('/abc?foo=(one)');
|
|
|
|
});
|
|
|
|
|
|
|
|
// Test special characters in general
|
|
|
|
|
2020-11-16 16:37:09 -05:00
|
|
|
// From https://tools.ietf.org/html/rfc3986
|
2018-02-20 18:08:41 -05:00
|
|
|
const unreserved = `abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~`;
|
|
|
|
|
2018-03-09 14:18:45 -05:00
|
|
|
it('should encode a minimal set of special characters in queryParams', () => {
|
2018-02-20 18:08:41 -05:00
|
|
|
const notEncoded = unreserved + `:@!$'*,();`;
|
|
|
|
const encode = ` +%&=#[]/?`;
|
|
|
|
const encoded = `%20%2B%25%26%3D%23%5B%5D%2F%3F`;
|
|
|
|
|
|
|
|
const parsed = url.parse('/foo');
|
|
|
|
|
|
|
|
parsed.queryParams = {notEncoded, encode};
|
|
|
|
|
|
|
|
expect(url.serialize(parsed)).toBe(`/foo?notEncoded=${notEncoded}&encode=${encoded}`);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should encode a minimal set of special characters in fragment', () => {
|
2018-03-09 14:18:45 -05:00
|
|
|
const notEncoded = unreserved + `:@!$'*,();+&=#/?`;
|
|
|
|
const encode = ' %<>`"[]';
|
|
|
|
const encoded = `%20%25%3C%3E%60%22%5B%5D`;
|
2018-02-20 18:08:41 -05:00
|
|
|
|
|
|
|
const parsed = url.parse('/foo');
|
|
|
|
|
|
|
|
parsed.fragment = notEncoded + encode;
|
|
|
|
|
|
|
|
expect(url.serialize(parsed)).toBe(`/foo#${notEncoded}${encoded}`);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should encode minimal special characters plus parens and semi-colon in matrix params',
|
|
|
|
() => {
|
|
|
|
const notEncoded = unreserved + `:@!$'*,&`;
|
|
|
|
const encode = ` /%=#()[];?+`;
|
|
|
|
const encoded = `%20%2F%25%3D%23%28%29%5B%5D%3B%3F%2B`;
|
|
|
|
|
|
|
|
const parsed = url.parse('/foo');
|
|
|
|
|
|
|
|
parsed.root.children[PRIMARY_OUTLET].segments[0].parameters = {notEncoded, encode};
|
|
|
|
|
|
|
|
expect(url.serialize(parsed)).toBe(`/foo;notEncoded=${notEncoded};encode=${encoded}`);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should encode special characters in the path the same as matrix params', () => {
|
|
|
|
const notEncoded = unreserved + `:@!$'*,&`;
|
|
|
|
const encode = ` /%=#()[];?+`;
|
|
|
|
const encoded = `%20%2F%25%3D%23%28%29%5B%5D%3B%3F%2B`;
|
|
|
|
|
|
|
|
const parsed = url.parse('/foo');
|
|
|
|
|
|
|
|
parsed.root.children[PRIMARY_OUTLET].segments[0].path = notEncoded + encode;
|
|
|
|
|
|
|
|
expect(url.serialize(parsed)).toBe(`/${notEncoded}${encoded}`);
|
2016-07-07 19:57:25 -04:00
|
|
|
});
|
2018-05-03 15:03:13 -04:00
|
|
|
|
|
|
|
it('should correctly encode ampersand in segments', () => {
|
|
|
|
const testUrl = '/parent&child';
|
|
|
|
|
|
|
|
const parsed = url.parse(testUrl);
|
|
|
|
|
|
|
|
expect(url.serialize(parsed)).toBe(testUrl);
|
|
|
|
});
|
2016-07-07 19:57:25 -04:00
|
|
|
});
|
2016-07-21 18:58:21 -04:00
|
|
|
|
|
|
|
describe('error handling', () => {
|
|
|
|
it('should throw when invalid characters inside children', () => {
|
|
|
|
expect(() => url.parse('/one/(left#one)'))
|
|
|
|
.toThrowError('Cannot parse url \'/one/(left#one)\'');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should throw when missing closing )', () => {
|
|
|
|
expect(() => url.parse('/one/(left')).toThrowError('Cannot parse url \'/one/(left\'');
|
|
|
|
});
|
|
|
|
});
|
2016-05-21 20:35:55 -04:00
|
|
|
});
|
|
|
|
|
2016-07-25 15:15:07 -04:00
|
|
|
function expectSegment(
|
|
|
|
segment: UrlSegmentGroup, expected: string, hasChildren: boolean = false): void {
|
|
|
|
if (segment.segments.filter(s => s.path === '').length > 0) {
|
|
|
|
throw new Error(`UrlSegments cannot be empty ${segment.segments}`);
|
2016-07-21 17:50:38 -04:00
|
|
|
}
|
2016-07-25 15:15:07 -04:00
|
|
|
const p = segment.segments.map(p => serializePath(p)).join('/');
|
2016-06-14 17:55:59 -04:00
|
|
|
expect(p).toEqual(expected);
|
|
|
|
expect(Object.keys(segment.children).length > 0).toEqual(hasChildren);
|
2016-05-21 20:35:55 -04:00
|
|
|
}
|