UNPKG

memen-url-join

Version:

Join urls and normalize as in path.join.

324 lines (269 loc) 7.54 kB
import assert from 'node:assert/strict'; import test from 'node:test'; import urlJoin from '../lib/url-join.js'; test('joins a simple URL', () => { assert.equal( urlJoin('http://www.google.com/', 'foo/bar', '?test=123'), 'http://www.google.com/foo/bar?test=123' ); }); test('joins a simple URL with new syntax', () => { assert.equal( urlJoin(['http://www.google.com/', 'foo/bar', '?test=123']), 'http://www.google.com/foo/bar?test=123' ); }); test('joins a hashbang', () => { assert.equal( urlJoin(['http://www.google.com', '#!', 'foo/bar', '?test=123']), 'http://www.google.com/#!/foo/bar?test=123' ); }); test('joins a protocol', () => { assert.equal( urlJoin('http:', 'www.google.com/', 'foo/bar', '?test=123'), 'http://www.google.com/foo/bar?test=123' ); }); test('joins a protocol with slashes', () => { assert.equal( urlJoin('http://', 'www.google.com/', 'foo/bar', '?test=123'), 'http://www.google.com/foo/bar?test=123' ); }); test('removes extra slashes', () => { assert.equal( urlJoin('http:', 'www.google.com///', 'foo/bar', '?test=123'), 'http://www.google.com/foo/bar?test=123' ); }); test('removes extra slashes in an encoded URL', () => { assert.equal( urlJoin('http:', 'www.google.com///', 'foo/bar', '?url=http%3A//Ftest.com'), 'http://www.google.com/foo/bar?url=http%3A//Ftest.com' ); assert.equal( urlJoin('http://a.com/23d04b3/', '/b/c.html'), 'http://a.com/23d04b3/b/c.html' ); assert.equal( urlJoin("/foo", "/", "bar", "?test=123"), "/foo/bar?test=123" ); }); test('joins anchors in URLs', () => { assert.equal( urlJoin('http:', 'www.google.com///', 'foo/bar', '?test=123', '#faaaaa'), 'http://www.google.com/foo/bar?test=123#faaaaa' ); }); test('joins protocol-relative URLs', () => { assert.equal( urlJoin('//www.google.com', 'foo/bar', '?test=123'), '//www.google.com/foo/bar?test=123' ); }); test('joins file protocol URLs', () => { assert.equal( urlJoin('file:/', 'android_asset', 'foo/bar'), 'file://android_asset/foo/bar' ); assert.equal( urlJoin('file:', '/android_asset', 'foo/bar'), 'file://android_asset/foo/bar' ); }); test('joins absolute file protocol URLs', () => { assert.equal( urlJoin('file:', '///android_asset', 'foo/bar'), 'file:///android_asset/foo/bar' ); assert.equal( urlJoin('file:///', 'android_asset', 'foo/bar'), 'file:///android_asset/foo/bar' ); assert.equal( urlJoin('file:///', '//android_asset', 'foo/bar'), 'file:///android_asset/foo/bar' ); assert.equal( urlJoin('file:///android_asset', 'foo/bar'), 'file:///android_asset/foo/bar' ); }); test('joins multiple query params', () => { assert.equal( urlJoin('http:', 'www.google.com///', 'foo/bar', '?test=123', '?key=456'), 'http://www.google.com/foo/bar?test=123&key=456' ); assert.equal( urlJoin('http:', 'www.google.com///', 'foo/bar', '?test=123', '?boom=value', '&key=456'), 'http://www.google.com/foo/bar?test=123&boom=value&key=456' ); assert.equal( urlJoin('http://example.org/x', '?a=1', '?b=2', '?c=3', '?d=4'), 'http://example.org/x?a=1&b=2&c=3&d=4' ); assert.equal( urlJoin('http:', 'www.google.com///', 'foo/bar', '&test=123', '&key=456'), 'http://www.google.com/foo/bar?test=123&key=456' ); assert.equal( urlJoin('http:', 'www.google.com///', 'foo/bar', '&test=123', '?key=456'), 'http://www.google.com/foo/bar?test=123&key=456' ); }); test('filters out empty query parameters', () => { assert.equal( urlJoin('http://google.com', '?'), 'http://google.com' ); assert.equal( urlJoin('http://google.com', '&'), 'http://google.com' ); }); test('joins slashes in paths', () => { assert.equal( urlJoin('http://example.org', 'a//', 'b//', 'A//', 'B//'), 'http://example.org/a/b/A/B/' ); }); test('joins colons in paths', () => { assert.equal( urlJoin('http://example.org/', ':foo:', 'bar'), 'http://example.org/:foo:/bar' ); }); test('joins a simple path without a URL', () => { assert.equal( urlJoin('/', 'test'), '/test' ); }); test('throws for segments that are not a string', () => { assert.throws( () => urlJoin(true), /Url must be a string. Received true/ ); assert.throws( () => urlJoin('http://blabla.com/', 1), /Url must be a string. Received 1/ ); assert.throws( () => urlJoin('http://blabla.com/', undefined, 'test'), /Url must be a string. Received undefined/ ); assert.throws( () => urlJoin('http://blabla.com/', null, 'test'), /Url must be a string. Received null/ ); assert.throws( () => urlJoin('http://blabla.com/', { foo: 123 }, 'test'), /Url must be a string. Received \[object Object\]/ ); }); test('joins a path with a colon', () => { assert.equal( urlJoin('/users/:userId', '/cars/:carId'), '/users/:userId/cars/:carId' ); }); test('joins slashes in the protocol', () => { assert.equal( urlJoin('http://example.org', 'a'), 'http://example.org/a' ); assert.equal( urlJoin('http:', '//example.org', 'a'), 'http://example.org/a' ); assert.equal( urlJoin('http:///example.org', 'a'), 'http://example.org/a' ); assert.equal( urlJoin('file:///example.org', 'a'), 'file:///example.org/a' ); assert.equal( urlJoin('file:example.org', 'a'), 'file://example.org/a' ); assert.equal( urlJoin('file:/', 'example.org', 'a'), 'file://example.org/a' ); assert.equal( urlJoin('file:', '/example.org', 'a'), 'file://example.org/a' ); assert.equal( urlJoin('file:', '//example.org', 'a'), 'file://example.org/a' ); }); test('skips empty strings', () => { assert.equal( urlJoin('http://foobar.com', '', 'test'), 'http://foobar.com/test' ); assert.equal( urlJoin('', 'http://foobar.com', '', 'test'), 'http://foobar.com/test' ); }); test('returns an empty string if no arguments are supplied', () => { assert.equal( urlJoin(), '' ); }); test('does not mutate the original input', () => { const input = ['http:', 'www.google.com/', 'foo/bar', '?test=123']; const expected = Array.from(input); urlJoin(input); assert.deepEqual(input, expected); }); test('does not replace query params after the hash', () => { assert.equal( urlJoin('http://example.com', '#a?b?c'), 'http://example.com#a?b?c' ); }); test('joins broken up query params', () => { assert.equal( urlJoin('http://example.com', '/foo/bar?', 'test=123'), 'http://example.com/foo/bar?test=123' ); }); test('joins broken up hash', () => { assert.equal( urlJoin('http://example.com', '/foo/bar#', 'some-hash'), 'http://example.com/foo/bar#some-hash' ); }); test('joins leading empty string', () => { assert.equal( urlJoin('', '/test'), '/test' ); }); test('joins a leading IPv6 hostname', () => { assert.equal( urlJoin('[2601:195:c381:3560::f42a]/', '/test'), '[2601:195:c381:3560::f42a]/test' ); }); test('joins a leading IPv6 host with an IPv4 address in the least significant 32 bits', () => { assert.equal( urlJoin('[2601:195:c381:3560::0.0.244.42]', '/test'), '[2601:195:c381:3560::0.0.244.42]/test' ); }); test('joins a protocol followed by an IPv6 host', () => { assert.equal( urlJoin('https://', '[2601:195:c381:3560::f42a]/', '/test'), 'https://[2601:195:c381:3560::f42a]/test' ); });