// Flags: --expose-internals 'use strict'; require('../common'); const URL = require('url').URL; const assert = require('assert'); const urlToOptions = require('internal/url').urlToOptions; // Tests below are not from WPT. const url = new URL('http://user:pass@foo.bar.com:21/aaa/zzz?l=24#test'); const oldParams = url.searchParams; // for test of [SameObject] // To retrieve enumerable but not necessarily own properties, // we need to use the for-in loop. const props = []; for (const prop in url) { props.push(prop); } // See: https://url.spec.whatwg.org/#api // https://heycam.github.io/webidl/#es-attributes // https://heycam.github.io/webidl/#es-stringifier const expected = ['toString', 'href', 'origin', 'protocol', 'username', 'password', 'host', 'hostname', 'port', 'pathname', 'search', 'searchParams', 'hash', 'toJSON']; assert.deepStrictEqual(props, expected); // href is writable (not readonly) and is stringifier assert.strictEqual(url.toString(), url.href); url.href = 'http://user:pass@foo.bar.com:21/aaa/zzz?l=25#test'; assert.strictEqual(url.href, 'http://user:pass@foo.bar.com:21/aaa/zzz?l=25#test'); assert.strictEqual(url.toString(), url.href); // Return true because it's configurable, but because the properties // are defined on the prototype per the spec, the deletion has no effect assert.strictEqual((delete url.href), true); assert.strictEqual(url.href, 'http://user:pass@foo.bar.com:21/aaa/zzz?l=25#test'); assert.strictEqual(url.searchParams, oldParams); // [SameObject] // searchParams is readonly. Under strict mode setting a // non-writable property should throw. // Note: this error message is subject to change in V8 updates assert.throws( () => url.origin = 'http://foo.bar.com:22', /^TypeError: Cannot set property origin of \[object URL\] which has only a getter$/ ); assert.strictEqual(url.origin, 'http://foo.bar.com:21'); assert.strictEqual(url.toString(), 'http://user:pass@foo.bar.com:21/aaa/zzz?l=25#test'); assert.strictEqual((delete url.origin), true); assert.strictEqual(url.origin, 'http://foo.bar.com:21'); // The following properties should be writable (not readonly) url.protocol = 'https:'; assert.strictEqual(url.protocol, 'https:'); assert.strictEqual(url.toString(), 'https://user:pass@foo.bar.com:21/aaa/zzz?l=25#test'); assert.strictEqual((delete url.protocol), true); assert.strictEqual(url.protocol, 'https:'); url.username = 'user2'; assert.strictEqual(url.username, 'user2'); assert.strictEqual(url.toString(), 'https://user2:pass@foo.bar.com:21/aaa/zzz?l=25#test'); assert.strictEqual((delete url.username), true); assert.strictEqual(url.username, 'user2'); url.password = 'pass2'; assert.strictEqual(url.password, 'pass2'); assert.strictEqual(url.toString(), 'https://user2:pass2@foo.bar.com:21/aaa/zzz?l=25#test'); assert.strictEqual((delete url.password), true); assert.strictEqual(url.password, 'pass2'); url.host = 'foo.bar.net:22'; assert.strictEqual(url.host, 'foo.bar.net:22'); assert.strictEqual(url.toString(), 'https://user2:pass2@foo.bar.net:22/aaa/zzz?l=25#test'); assert.strictEqual((delete url.host), true); assert.strictEqual(url.host, 'foo.bar.net:22'); url.hostname = 'foo.bar.org'; assert.strictEqual(url.hostname, 'foo.bar.org'); assert.strictEqual(url.toString(), 'https://user2:pass2@foo.bar.org:22/aaa/zzz?l=25#test'); assert.strictEqual((delete url.hostname), true); assert.strictEqual(url.hostname, 'foo.bar.org'); url.port = '23'; assert.strictEqual(url.port, '23'); assert.strictEqual(url.toString(), 'https://user2:pass2@foo.bar.org:23/aaa/zzz?l=25#test'); assert.strictEqual((delete url.port), true); assert.strictEqual(url.port, '23'); url.pathname = '/aaa/bbb'; assert.strictEqual(url.pathname, '/aaa/bbb'); assert.strictEqual(url.toString(), 'https://user2:pass2@foo.bar.org:23/aaa/bbb?l=25#test'); assert.strictEqual((delete url.pathname), true); assert.strictEqual(url.pathname, '/aaa/bbb'); url.search = '?k=99'; assert.strictEqual(url.search, '?k=99'); assert.strictEqual(url.toString(), 'https://user2:pass2@foo.bar.org:23/aaa/bbb?k=99#test'); assert.strictEqual((delete url.search), true); assert.strictEqual(url.search, '?k=99'); url.hash = '#abcd'; assert.strictEqual(url.hash, '#abcd'); assert.strictEqual(url.toString(), 'https://user2:pass2@foo.bar.org:23/aaa/bbb?k=99#abcd'); assert.strictEqual((delete url.hash), true); assert.strictEqual(url.hash, '#abcd'); // searchParams is readonly. Under strict mode setting a // non-writable property should throw. // Note: this error message is subject to change in V8 updates assert.throws( () => url.searchParams = '?k=88', /^TypeError: Cannot set property searchParams of \[object URL\] which has only a getter$/ ); assert.strictEqual(url.searchParams, oldParams); assert.strictEqual(url.toString(), 'https://user2:pass2@foo.bar.org:23/aaa/bbb?k=99#abcd'); assert.strictEqual((delete url.searchParams), true); assert.strictEqual(url.searchParams, oldParams); // Test urlToOptions { const opts = urlToOptions(new URL('http://user:pass@foo.bar.com:21/aaa/zzz?l=24#test')); assert.strictEqual(opts instanceof URL, false); assert.strictEqual(opts.protocol, 'http:'); assert.strictEqual(opts.auth, 'user:pass'); assert.strictEqual(opts.hostname, 'foo.bar.com'); assert.strictEqual(opts.port, 21); assert.strictEqual(opts.path, '/aaa/zzz?l=24'); assert.strictEqual(opts.pathname, '/aaa/zzz'); assert.strictEqual(opts.search, '?l=24'); assert.strictEqual(opts.hash, '#test'); } // Test special origins [ { expected: 'https://whatwg.org', url: 'blob:https://whatwg.org/d0360e2f-caee-469f-9a2f-87d5b0456f6f' }, { expected: 'ftp://example.org', url: 'ftp://example.org/foo' }, { expected: 'gopher://gopher.quux.org', url: 'gopher://gopher.quux.org/1/' }, { expected: 'http://example.org', url: 'http://example.org/foo' }, { expected: 'https://example.org', url: 'https://example.org/foo' }, { expected: 'ws://example.org', url: 'ws://example.org/foo' }, { expected: 'wss://example.org', url: 'wss://example.org/foo' }, { expected: 'null', url: 'file:///tmp/mock/path' }, { expected: 'null', url: 'npm://nodejs/rules' } ].forEach((test) => { assert.strictEqual(new URL(test.url).origin, test.expected); });