101 lines
3.2 KiB
TypeScript
101 lines
3.2 KiB
TypeScript
// Copyright 2021 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
import { assert } from 'chai';
|
|
import { size } from '../../util/iterables';
|
|
|
|
import {
|
|
maybeParseUrl,
|
|
setUrlSearchParams,
|
|
urlPathFromComponents,
|
|
} from '../../util/url';
|
|
|
|
describe('URL utilities', () => {
|
|
describe('maybeParseUrl', () => {
|
|
it('parses valid URLs', () => {
|
|
[
|
|
'https://example.com',
|
|
'https://example.com:123/pathname?query=string#hash',
|
|
'file:///path/to/file.txt',
|
|
].forEach(href => {
|
|
assert.deepEqual(maybeParseUrl(href), new URL(href));
|
|
});
|
|
});
|
|
|
|
it('returns undefined for invalid URLs', () => {
|
|
['', 'example.com'].forEach(href => {
|
|
assert.isUndefined(maybeParseUrl(href));
|
|
});
|
|
});
|
|
|
|
it('handles non-strings for compatibility, returning undefined', () => {
|
|
[undefined, null, 123, ['https://example.com']].forEach(value => {
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
assert.isUndefined(maybeParseUrl(value as any));
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('setUrlSearchParams', () => {
|
|
it('returns a new URL with updated search params', () => {
|
|
const params = {
|
|
normal_string: 'foo',
|
|
empty_string: '',
|
|
number: 123,
|
|
true_bool: true,
|
|
false_bool: false,
|
|
array: ['ok', 'wow'],
|
|
stringified: { toString: () => 'bar' },
|
|
};
|
|
|
|
const newUrl = setUrlSearchParams(
|
|
new URL('https://example.com/path?should_be=overwritten#hash'),
|
|
params
|
|
);
|
|
|
|
assert(newUrl.href.startsWith('https://example.com/path?'));
|
|
assert.strictEqual(newUrl.hash, '#hash');
|
|
|
|
assert.strictEqual(
|
|
size(newUrl.searchParams.entries()),
|
|
Object.keys(params).length
|
|
);
|
|
assert.strictEqual(newUrl.searchParams.get('normal_string'), 'foo');
|
|
assert.strictEqual(newUrl.searchParams.get('empty_string'), '');
|
|
assert.strictEqual(newUrl.searchParams.get('number'), '123');
|
|
assert.strictEqual(newUrl.searchParams.get('true_bool'), 'true');
|
|
assert.strictEqual(newUrl.searchParams.get('false_bool'), 'false');
|
|
assert.strictEqual(newUrl.searchParams.get('array'), 'ok,wow');
|
|
assert.strictEqual(newUrl.searchParams.get('stringified'), 'bar');
|
|
});
|
|
|
|
it("doesn't touch the original URL or its params", () => {
|
|
const originalHref = 'https://example.com/path?query=string';
|
|
const originalUrl = new URL(originalHref);
|
|
|
|
const params = { foo: 'bar' };
|
|
|
|
const newUrl = setUrlSearchParams(originalUrl, params);
|
|
|
|
assert.notStrictEqual(originalUrl, newUrl);
|
|
assert.strictEqual(originalUrl.href, originalHref);
|
|
|
|
params.foo = 'should be ignored';
|
|
assert.strictEqual(newUrl.search, '?foo=bar');
|
|
});
|
|
});
|
|
|
|
describe('urlPathFromComponents', () => {
|
|
it('returns / if no components are provided', () => {
|
|
assert.strictEqual(urlPathFromComponents([]), '/');
|
|
});
|
|
|
|
it('joins components, percent-encoding them and removing empty components', () => {
|
|
const components = ['foo', '', '~', 'bar / baz qúx'];
|
|
assert.strictEqual(
|
|
urlPathFromComponents(components),
|
|
'/foo/~/bar%20%2F%20baz%20q%C3%BAx'
|
|
);
|
|
});
|
|
});
|
|
});
|