renovate/lib/util/url.spec.ts

228 lines
10 KiB
TypeScript

import {
createURLFromHostOrURL,
ensurePathPrefix,
ensureTrailingSlash,
getQueryString,
isHttpUrl,
joinUrlParts,
massageHostUrl,
parseLinkHeader,
parseUrl,
replaceUrlPath,
resolveBaseUrl,
trimSlashes,
trimTrailingSlash,
} from './url';
describe('util/url', () => {
it.each`
baseUrl | x | result
${'http://foo.io'} | ${''} | ${'http://foo.io'}
${'http://foo.io/'} | ${''} | ${'http://foo.io'}
${'http://foo.io'} | ${'/'} | ${'http://foo.io/'}
${'http://foo.io/'} | ${'/'} | ${'http://foo.io/'}
${'http://foo.io'} | ${'/aaa'} | ${'http://foo.io/aaa'}
${'http://foo.io'} | ${'aaa'} | ${'http://foo.io/aaa'}
${'http://foo.io/'} | ${'/aaa'} | ${'http://foo.io/aaa'}
${'http://foo.io/'} | ${'aaa'} | ${'http://foo.io/aaa'}
${'http://foo.io'} | ${'/aaa/'} | ${'http://foo.io/aaa/'}
${'http://foo.io'} | ${'aaa/'} | ${'http://foo.io/aaa/'}
${'http://foo.io/'} | ${'/aaa/'} | ${'http://foo.io/aaa/'}
${'http://foo.io/'} | ${'aaa/'} | ${'http://foo.io/aaa/'}
${'http://foo.io/aaa'} | ${'/bbb'} | ${'http://foo.io/aaa/bbb'}
${'http://foo.io/aaa'} | ${'bbb'} | ${'http://foo.io/aaa/bbb'}
${'http://foo.io/aaa/'} | ${'/bbb'} | ${'http://foo.io/aaa/bbb'}
${'http://foo.io/aaa/'} | ${'bbb'} | ${'http://foo.io/aaa/bbb'}
${'http://foo.io/aaa'} | ${'/bbb/'} | ${'http://foo.io/aaa/bbb/'}
${'http://foo.io/aaa'} | ${'bbb/'} | ${'http://foo.io/aaa/bbb/'}
${'http://foo.io/aaa/'} | ${'/bbb/'} | ${'http://foo.io/aaa/bbb/'}
${'http://foo.io/aaa/'} | ${'bbb/'} | ${'http://foo.io/aaa/bbb/'}
${'http://foo.io'} | ${'http://bar.io/bbb'} | ${'http://bar.io/bbb'}
${'http://foo.io/'} | ${'http://bar.io/bbb'} | ${'http://bar.io/bbb'}
${'http://foo.io/aaa'} | ${'http://bar.io/bbb'} | ${'http://bar.io/bbb'}
${'http://foo.io/aaa/'} | ${'http://bar.io/bbb'} | ${'http://bar.io/bbb'}
${'http://foo.io'} | ${'http://bar.io/bbb/'} | ${'http://bar.io/bbb/'}
${'http://foo.io/'} | ${'http://bar.io/bbb/'} | ${'http://bar.io/bbb/'}
${'http://foo.io/aaa'} | ${'http://bar.io/bbb/'} | ${'http://bar.io/bbb/'}
${'http://foo.io/aaa/'} | ${'http://bar.io/bbb/'} | ${'http://bar.io/bbb/'}
${'http://foo.io'} | ${'aaa?bbb=z'} | ${'http://foo.io/aaa?bbb=z'}
${'http://foo.io'} | ${'/aaa?bbb=z'} | ${'http://foo.io/aaa?bbb=z'}
${'http://foo.io/'} | ${'aaa?bbb=z'} | ${'http://foo.io/aaa?bbb=z'}
${'http://foo.io/'} | ${'/aaa?bbb=z'} | ${'http://foo.io/aaa?bbb=z'}
${'http://foo.io'} | ${'aaa/?bbb=z'} | ${'http://foo.io/aaa?bbb=z'}
`('$baseUrl + $x => $result', ({ baseUrl, x, result }) => {
expect(resolveBaseUrl(baseUrl, x)).toBe(result);
});
it.each`
baseUrl | x | result
${'http://foo.io'} | ${''} | ${'http://foo.io'}
${'http://foo.io/'} | ${''} | ${'http://foo.io'}
${'http://foo.io'} | ${'/'} | ${'http://foo.io/'}
${'http://foo.io/'} | ${'/'} | ${'http://foo.io/'}
${'http://foo.io'} | ${'/aaa'} | ${'http://foo.io/aaa'}
${'http://foo.io'} | ${'aaa'} | ${'http://foo.io/aaa'}
${'http://foo.io/'} | ${'/aaa'} | ${'http://foo.io/aaa'}
${'http://foo.io/'} | ${'aaa'} | ${'http://foo.io/aaa'}
${'http://foo.io'} | ${'/aaa/'} | ${'http://foo.io/aaa/'}
${'http://foo.io'} | ${'aaa/'} | ${'http://foo.io/aaa/'}
${'http://foo.io/'} | ${'/aaa/'} | ${'http://foo.io/aaa/'}
${'http://foo.io/'} | ${'aaa/'} | ${'http://foo.io/aaa/'}
${'http://foo.io/aaa'} | ${'/bbb'} | ${'http://foo.io/bbb'}
${'http://foo.io/aaa'} | ${'bbb'} | ${'http://foo.io/bbb'}
${'http://foo.io/aaa/'} | ${'/bbb'} | ${'http://foo.io/bbb'}
${'http://foo.io/aaa/'} | ${'bbb'} | ${'http://foo.io/bbb'}
${'http://foo.io/aaa'} | ${'/bbb/'} | ${'http://foo.io/bbb/'}
${'http://foo.io/aaa'} | ${'bbb/'} | ${'http://foo.io/bbb/'}
${'http://foo.io/aaa/'} | ${'/bbb/'} | ${'http://foo.io/bbb/'}
${'http://foo.io/aaa/'} | ${'bbb/'} | ${'http://foo.io/bbb/'}
${'http://foo.io'} | ${'http://bar.io/bbb'} | ${'http://bar.io/bbb'}
${'http://foo.io/'} | ${'http://bar.io/bbb'} | ${'http://bar.io/bbb'}
${'http://foo.io/aaa'} | ${'http://bar.io/bbb'} | ${'http://bar.io/bbb'}
${'http://foo.io/aaa/'} | ${'http://bar.io/bbb'} | ${'http://bar.io/bbb'}
${'http://foo.io'} | ${'http://bar.io/bbb/'} | ${'http://bar.io/bbb/'}
${'http://foo.io/'} | ${'http://bar.io/bbb/'} | ${'http://bar.io/bbb/'}
${'http://foo.io/aaa'} | ${'http://bar.io/bbb/'} | ${'http://bar.io/bbb/'}
${'http://foo.io/aaa/'} | ${'http://bar.io/bbb/'} | ${'http://bar.io/bbb/'}
${'http://foo.io'} | ${'aaa?bbb=z'} | ${'http://foo.io/aaa?bbb=z'}
${'http://foo.io'} | ${'/aaa?bbb=z'} | ${'http://foo.io/aaa?bbb=z'}
${'http://foo.io/'} | ${'aaa?bbb=z'} | ${'http://foo.io/aaa?bbb=z'}
${'http://foo.io/'} | ${'/aaa?bbb=z'} | ${'http://foo.io/aaa?bbb=z'}
${'http://foo.io'} | ${'aaa/?bbb=z'} | ${'http://foo.io/aaa?bbb=z'}
`('replaceUrlPath("$baseUrl", "$x") => $result', ({ baseUrl, x, result }) => {
expect(replaceUrlPath(baseUrl, x)).toBe(result);
expect(replaceUrlPath(new URL(baseUrl), x)).toBe(result);
});
it('getQueryString', () => {
expect(getQueryString({ a: 1, b: [1, 2] })).toBe('a=1&b=1&b=2');
});
it('validates http-based URLs', () => {
expect(isHttpUrl(undefined)).toBeFalse();
expect(isHttpUrl('')).toBeFalse();
expect(isHttpUrl(null)).toBeFalse();
expect(isHttpUrl('foo')).toBeFalse();
expect(isHttpUrl('ssh://github.com')).toBeFalse();
expect(isHttpUrl('http://github.com')).toBeTrue();
expect(isHttpUrl('https://github.com')).toBeTrue();
});
it('parses URL', () => {
expect(parseUrl(null)).toBeNull();
expect(parseUrl(undefined)).toBeNull();
const url = parseUrl('https://github.com/renovatebot/renovate');
expect(url?.protocol).toBe('https:');
expect(url?.host).toBe('github.com');
expect(url?.pathname).toBe('/renovatebot/renovate');
});
it('trimTrailingSlash', () => {
expect(trimTrailingSlash('foo')).toBe('foo');
expect(trimTrailingSlash('/foo/bar')).toBe('/foo/bar');
expect(trimTrailingSlash('foo/')).toBe('foo');
expect(trimTrailingSlash('foo//////')).toBe('foo');
});
it('trimSlashes', () => {
expect(trimSlashes('foo')).toBe('foo');
expect(trimSlashes('/foo')).toBe('foo');
expect(trimSlashes('foo/')).toBe('foo');
expect(trimSlashes('//////foo//////')).toBe('foo');
expect(trimSlashes('foo/bar')).toBe('foo/bar');
expect(trimSlashes('/foo/bar')).toBe('foo/bar');
expect(trimSlashes('foo/bar/')).toBe('foo/bar');
expect(trimSlashes('/foo/bar/')).toBe('foo/bar');
});
it('ensureTrailingSlash', () => {
expect(ensureTrailingSlash('')).toBe('/');
expect(ensureTrailingSlash('/')).toBe('/');
});
it('ensures path prefix', () => {
expect(ensurePathPrefix('https://index.docker.io', '/v2')).toBe(
'https://index.docker.io/v2/',
);
expect(ensurePathPrefix('https://index.docker.io/v2', '/v2')).toBe(
'https://index.docker.io/v2',
);
expect(
ensurePathPrefix('https://index.docker.io/v2/something', '/v2'),
).toBe('https://index.docker.io/v2/something');
expect(ensurePathPrefix('https://index.docker.io:443', '/v2')).toBe(
'https://index.docker.io/v2/',
);
expect(
ensurePathPrefix('https://index.docker.io/something?with=query', '/v2'),
).toBe('https://index.docker.io/v2/something?with=query');
});
it('joinUrlParts', () => {
const registryUrl = 'https://some.test';
expect(joinUrlParts(registryUrl, 'foo')).toBe(`${registryUrl}/foo`);
expect(joinUrlParts(registryUrl, '/?foo')).toBe(`${registryUrl}?foo`);
expect(joinUrlParts(registryUrl, '/foo/bar/')).toBe(
`${registryUrl}/foo/bar/`,
);
expect(joinUrlParts(`${registryUrl}/foo/`, '/foo/bar')).toBe(
`${registryUrl}/foo/foo/bar`,
);
expect(joinUrlParts(`${registryUrl}/api/`, '/foo/bar')).toBe(
`${registryUrl}/api/foo/bar`,
);
expect(joinUrlParts('foo//////')).toBe('foo/');
});
it('createURLFromHostOrURL', () => {
expect(createURLFromHostOrURL('https://some.test')).toEqual(
new URL('https://some.test/'),
);
expect(createURLFromHostOrURL('some.test')).toEqual(
new URL('https://some.test/'),
);
});
it('parseLinkHeader', () => {
expect(parseLinkHeader(null)).toBeNull();
expect(parseLinkHeader(' '.repeat(2001))).toBeNull();
expect(
parseLinkHeader(
'<https://api.github.com/user/9287/repos?page=3&per_page=100>; rel="next",' +
'<https://api.github.com/user/9287/repos?page=1&per_page=100>; rel="prev"; pet="cat", ' +
'<https://api.github.com/user/9287/repos?page=5&per_page=100>; rel="last"',
),
).toStrictEqual({
next: {
page: '3',
per_page: '100',
rel: 'next',
url: 'https://api.github.com/user/9287/repos?page=3&per_page=100',
},
prev: {
page: '1',
per_page: '100',
rel: 'prev',
pet: 'cat',
url: 'https://api.github.com/user/9287/repos?page=1&per_page=100',
},
last: {
page: '5',
per_page: '100',
rel: 'last',
url: 'https://api.github.com/user/9287/repos?page=5&per_page=100',
},
});
});
it('massageHostUrl', () => {
expect(massageHostUrl('domain.com')).toBe('domain.com');
expect(massageHostUrl('domain.com:8080')).toBe('https://domain.com:8080');
expect(massageHostUrl('domain.com/some/path')).toBe(
'https://domain.com/some/path',
);
expect(massageHostUrl('https://domain.com')).toBe('https://domain.com');
});
});