diff --git a/doc/api/errors.md b/doc/api/errors.md
index 0d02fe58707355..db6afb315877e5 100644
--- a/doc/api/errors.md
+++ b/doc/api/errors.md
@@ -562,6 +562,13 @@ found [here][online].
## Node.js Error Codes
+
+### ERR_ARG_NOT_ITERABLE
+
+The `'ERR_ARG_NOT_ITERABLE'` error code is used generically to identify that an
+iterable argument (i.e. a value that works with `for...of` loops) is required,
+but not provided to a Node.js API.
+
### ERR_INVALID_ARG_TYPE
@@ -574,6 +581,79 @@ an argument of the wrong type has been passed to a Node.js API.
The `'ERR_INVALID_CALLBACK'` error code is used generically to identify that
a callback function is required and has not been provided to a Node.js API.
+
+### ERR_INVALID_FILE_URL_HOST
+
+An error with the `'ERR_INVALID_FILE_URL_HOST'` code may be thrown when a
+Node.js API that consumes `file:` URLs (such as certain functions in the
+[`fs`][] module) encounters a file URL with an incompatible host. Currently,
+this situation can only occur on Unix-like systems, where only `localhost` or
+an empty host is supported.
+
+
+### ERR_INVALID_FILE_URL_PATH
+
+An error with the `'ERR_INVALID_FILE_URL_PATH'` code may be thrown when a
+Node.js API that consumes `file:` URLs (such as certain functions in the
+[`fs`][] module) encounters a file URL with an incompatible path. The exact
+semantics for determining whether a path can be used is platform-dependent.
+
+
+### ERR_INVALID_THIS
+
+The `'ERR_INVALID_THIS'` error code is used generically to identify that a
+Node.js API function is called with an incompatible `this` value. Its use is
+currently limited to the [WHATWG URL API][] to satisfy specification
+requirements, but may be expanded to other areas of the Node.js API in the
+future.
+
+Example:
+
+```js
+const { URLSearchParams } = require('url');
+const urlSearchParams = new URLSearchParams('foo=bar&baz=new');
+
+const buf = Buffer.alloc(1);
+urlSearchParams.has.call(buf, 'foo');
+ // Throws a TypeError with code 'ERR_INVALID_THIS'
+```
+
+
+### ERR_INVALID_TUPLE
+
+An error with code `'ERR_INVALID_TUPLE'` is thrown when an element in the
+`iterable` provided to the [WHATWG][WHATWG URL API] [`URLSearchParams`
+constructor][`new URLSearchParams(iterable)`] does not represent a name/value
+tuple -- that is, if an element is not iterable, or does not consist of exactly
+two elements.
+
+
+### ERR_INVALID_URL
+
+An error using the `'ERR_INVALID_URL'` code is thrown when an invalid URL is
+passed to the [WHATWG][WHATWG URL API] [`URL` constructor][`new URL(input)`] to
+be parsed. The thrown error object typically has an additional property
+`'input'` that contains the URL that failed to parse.
+
+
+### ERR_INVALID_URL_SCHEME
+
+The code `'ERR_INVALID_URL_SCHEME'` is used generically to signify an attempt
+to use a URL of an incompatible scheme (aka protocol) for a specific purpose.
+It is currently only used in the [WHATWG URL API][] support in the [`fs`][]
+module (which only accepts URLs with `'file'` scheme), but may be used in other
+Node.js APIs as well in the future.
+
+
+### ERR_MISSING_ARGS
+
+The `'ERR_MISSING_ARGS'` error code is a generic error code for instances where
+a required argument of a Node.js API is not passed. This is currently only used
+in the [WHATWG URL API][] for strict compliance with the specification (which
+in some cases may accept `func(undefined)` but not `func()`). In most native
+Node.js APIs, `func(undefined)` and `func()` are treated identically, and the
+[`ERR_INVALID_ARG_TYPE`][] error code may be used instead.
+
### ERR_STDERR_CLOSE
@@ -626,11 +706,15 @@ likely an indication of a bug within Node.js itself.
[`process.on('uncaughtException')`]: process.html#process_event_uncaughtexception
[domains]: domain.html
[event emitter-based]: events.html#events_class_eventemitter
+[`ERR_INVALID_ARG_TYPE`]: #ERR_INVALID_ARG_TYPE
[file descriptors]: https://en.wikipedia.org/wiki/File_descriptor
[Node.js Error Codes]: #nodejs-error-codes
[online]: http://man7.org/linux/man-pages/man3/errno.3.html
[stream-based]: stream.html
[syscall]: http://man7.org/linux/man-pages/man2/syscall.2.html
[try-catch]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch
+[`new URL(input)`]: url.html#url_constructor_new_url_input_base
+[`new URLSearchParams(iterable)`]: url.html#url_constructor_new_urlsearchparams_iterable
[V8's stack trace API]: https://github.com/v8/v8/wiki/Stack-Trace-API
[vm]: vm.html
+[WHATWG URL API]: url.html#url_the_whatwg_url_api
diff --git a/lib/internal/errors.js b/lib/internal/errors.js
index a124a5f65d5738..f27132d16ef796 100644
--- a/lib/internal/errors.js
+++ b/lib/internal/errors.js
@@ -79,9 +79,19 @@ module.exports = exports = {
// Any error code added here should also be added to the documentation
//
// Note: Please try to keep these in alphabetical order
+E('ERR_ARG_NOT_ITERABLE', '%s must be iterable');
E('ERR_ASSERTION', (msg) => msg);
E('ERR_INVALID_ARG_TYPE', invalidArgType);
E('ERR_INVALID_CALLBACK', 'callback must be a function');
+E('ERR_INVALID_FILE_URL_HOST', 'File URL host must %s');
+E('ERR_INVALID_FILE_URL_PATH', 'File URL path must %s');
+E('ERR_INVALID_THIS', 'Value of this must be of type %s');
+E('ERR_INVALID_TUPLE', '%s must be an iterable %s tuple');
+E('ERR_INVALID_URL',
+ (input) => `Invalid URL${input !== undefined ? `: ${input}` : ''}`);
+E('ERR_INVALID_URL_SCHEME',
+ (expected) => `The URL must be ${oneOf(expected, 'scheme')}`);
+E('ERR_MISSING_ARGS', missingArgs);
E('ERR_STDERR_CLOSE', 'process.stderr cannot be closed');
E('ERR_STDOUT_CLOSE', 'process.stdout cannot be closed');
E('ERR_UNKNOWN_STDIN_TYPE', 'Unknown stdin file type');
@@ -98,6 +108,26 @@ function invalidArgType(name, expected, actual) {
return msg;
}
+function missingArgs(...args) {
+ assert(args.length > 0, 'At least one arg needs to be specified');
+ let msg = 'The ';
+ const len = args.length;
+ args = args.map((a) => `"${a}"`);
+ switch (len) {
+ case 1:
+ msg += `${args[0]} argument`;
+ break;
+ case 2:
+ msg += `${args[0]} and ${args[1]} arguments`;
+ break;
+ default:
+ msg += args.slice(0, len - 1).join(', ');
+ msg += `, and ${args[len - 1]} arguments`;
+ break;
+ }
+ return `${msg} must be specified`;
+}
+
function oneOf(expected, thing) {
assert(expected, 'expected is required');
assert(typeof thing === 'string', 'thing is required');
diff --git a/lib/internal/url.js b/lib/internal/url.js
index 25a4f51ba23542..142e6a51d65b1e 100644
--- a/lib/internal/url.js
+++ b/lib/internal/url.js
@@ -6,6 +6,7 @@ const {
isHexTable
} = require('internal/querystring');
const { getConstructorOf } = require('internal/util');
+const errors = require('internal/errors');
const binding = process.binding('url');
const context = Symbol('context');
const cannotBeBase = Symbol('cannot-be-base');
@@ -14,9 +15,9 @@ const cannotHaveUsernamePasswordPort =
const special = Symbol('special');
const searchParams = Symbol('query');
const querystring = require('querystring');
-const os = require('os');
-const isWindows = process.platform === 'win32';
+const { platform } = process;
+const isWindows = platform === 'win32';
const kFormat = Symbol('format');
@@ -88,7 +89,7 @@ function onParseComplete(flags, protocol, username, password,
}
function onParseError(flags, input) {
- const error = new TypeError('Invalid URL: ' + input);
+ const error = new errors.TypeError('ERR_INVALID_URL', input);
error.input = input;
throw error;
}
@@ -202,7 +203,7 @@ class URL {
[util.inspect.custom](depth, opts) {
if (this == null ||
Object.getPrototypeOf(this[context]) !== URLContext.prototype) {
- throw new TypeError('Value of `this` is not a URL');
+ throw new errors.TypeError('ERR_INVALID_THIS', 'URL');
}
const ctx = this[context];
@@ -247,7 +248,7 @@ Object.defineProperties(URL.prototype, {
// eslint-disable-next-line func-name-matching
value: function format(options) {
if (options && typeof options !== 'object')
- throw new TypeError('options must be an object');
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'options', 'object');
options = Object.assign({
fragment: true,
unicode: false,
@@ -810,7 +811,7 @@ class URLSearchParams {
this[searchParams] = childParams.slice();
} else if (method !== null && method !== undefined) {
if (typeof method !== 'function') {
- throw new TypeError('Query pairs must be iterable');
+ throw new errors.TypeError('ERR_ARG_NOT_ITERABLE', 'Query pairs');
}
// sequence>
@@ -819,7 +820,8 @@ class URLSearchParams {
for (const pair of init) {
if (typeof pair !== 'object' ||
typeof pair[Symbol.iterator] !== 'function') {
- throw new TypeError('Each query pair must be iterable');
+ throw new errors.TypeError('ERR_INVALID_TUPLE', 'Each query pair',
+ 'name/value');
}
pairs.push(Array.from(pair));
}
@@ -827,7 +829,8 @@ class URLSearchParams {
this[searchParams] = [];
for (const pair of pairs) {
if (pair.length !== 2) {
- throw new TypeError('Each query pair must be a name/value tuple');
+ throw new errors.TypeError('ERR_INVALID_TUPLE', 'Each query pair',
+ 'name/value');
}
const key = toUSVString(pair[0]);
const value = toUSVString(pair[1]);
@@ -855,7 +858,7 @@ class URLSearchParams {
[util.inspect.custom](recurseTimes, ctx) {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
- throw new TypeError('Value of `this` is not a URLSearchParams');
+ throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams');
}
if (typeof recurseTimes === 'number' && recurseTimes < 0)
@@ -920,10 +923,10 @@ function merge(out, start, mid, end, lBuffer, rBuffer) {
defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
append(name, value) {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
- throw new TypeError('Value of `this` is not a URLSearchParams');
+ throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams');
}
if (arguments.length < 2) {
- throw new TypeError('"name" and "value" arguments must be specified');
+ throw new errors.TypeError('ERR_MISSING_ARGS', 'name', 'value');
}
name = toUSVString(name);
@@ -934,10 +937,10 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
delete(name) {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
- throw new TypeError('Value of `this` is not a URLSearchParams');
+ throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams');
}
if (arguments.length < 1) {
- throw new TypeError('"name" argument must be specified');
+ throw new errors.TypeError('ERR_MISSING_ARGS', 'name');
}
const list = this[searchParams];
@@ -955,10 +958,10 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
get(name) {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
- throw new TypeError('Value of `this` is not a URLSearchParams');
+ throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams');
}
if (arguments.length < 1) {
- throw new TypeError('"name" argument must be specified');
+ throw new errors.TypeError('ERR_MISSING_ARGS', 'name');
}
const list = this[searchParams];
@@ -973,10 +976,10 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
getAll(name) {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
- throw new TypeError('Value of `this` is not a URLSearchParams');
+ throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams');
}
if (arguments.length < 1) {
- throw new TypeError('"name" argument must be specified');
+ throw new errors.TypeError('ERR_MISSING_ARGS', 'name');
}
const list = this[searchParams];
@@ -992,10 +995,10 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
has(name) {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
- throw new TypeError('Value of `this` is not a URLSearchParams');
+ throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams');
}
if (arguments.length < 1) {
- throw new TypeError('"name" argument must be specified');
+ throw new errors.TypeError('ERR_MISSING_ARGS', 'name');
}
const list = this[searchParams];
@@ -1010,10 +1013,10 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
set(name, value) {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
- throw new TypeError('Value of `this` is not a URLSearchParams');
+ throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams');
}
if (arguments.length < 2) {
- throw new TypeError('"name" and "value" arguments must be specified');
+ throw new errors.TypeError('ERR_MISSING_ARGS', 'name', 'value');
}
const list = this[searchParams];
@@ -1098,7 +1101,7 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
// must be set to `entries`.
entries() {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
- throw new TypeError('Value of `this` is not a URLSearchParams');
+ throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams');
}
return createSearchParamsIterator(this, 'key+value');
@@ -1106,10 +1109,10 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
forEach(callback, thisArg = undefined) {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
- throw new TypeError('Value of `this` is not a URLSearchParams');
+ throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams');
}
if (typeof callback !== 'function') {
- throw new TypeError('"callback" argument must be a function');
+ throw new errors.TypeError('ERR_INVALID_CALLBACK');
}
let list = this[searchParams];
@@ -1128,7 +1131,7 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
// https://heycam.github.io/webidl/#es-iterable
keys() {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
- throw new TypeError('Value of `this` is not a URLSearchParams');
+ throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams');
}
return createSearchParamsIterator(this, 'key');
@@ -1136,7 +1139,7 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
values() {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
- throw new TypeError('Value of `this` is not a URLSearchParams');
+ throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams');
}
return createSearchParamsIterator(this, 'value');
@@ -1146,7 +1149,7 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
// https://url.spec.whatwg.org/#urlsearchparams-stringification-behavior
toString() {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
- throw new TypeError('Value of `this` is not a URLSearchParams');
+ throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams');
}
return serializeParams(this[searchParams]);
@@ -1178,7 +1181,7 @@ defineIDLClass(URLSearchParamsIteratorPrototype, 'URLSearchParamsIterator', {
next() {
if (!this ||
Object.getPrototypeOf(this) !== URLSearchParamsIteratorPrototype) {
- throw new TypeError('Value of `this` is not a URLSearchParamsIterator');
+ throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParamsIterator');
}
const {
@@ -1215,7 +1218,7 @@ defineIDLClass(URLSearchParamsIteratorPrototype, 'URLSearchParamsIterator', {
},
[util.inspect.custom](recurseTimes, ctx) {
if (this == null || this[context] == null || this[context].target == null)
- throw new TypeError('Value of `this` is not a URLSearchParamsIterator');
+ throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParamsIterator');
if (typeof recurseTimes === 'number' && recurseTimes < 0)
return ctx.stylize('[Object]', 'special');
@@ -1254,7 +1257,7 @@ defineIDLClass(URLSearchParamsIteratorPrototype, 'URLSearchParamsIterator', {
function domainToASCII(domain) {
if (arguments.length < 1)
- throw new TypeError('"domain" argument must be specified');
+ throw new errors.TypeError('ERR_MISSING_ARGS', 'domain');
// toUSVString is not needed.
return binding.domainToASCII(`${domain}`);
@@ -1262,7 +1265,7 @@ function domainToASCII(domain) {
function domainToUnicode(domain) {
if (arguments.length < 1)
- throw new TypeError('"domain" argument must be specified');
+ throw new errors.TypeError('ERR_MISSING_ARGS', 'domain');
// toUSVString is not needed.
return binding.domainToUnicode(`${domain}`);
@@ -1299,8 +1302,8 @@ function getPathFromURLWin32(url) {
var third = pathname.codePointAt(n + 2) | 0x20;
if ((pathname[n + 1] === '2' && third === 102) || // 2f 2F /
(pathname[n + 1] === '5' && third === 99)) { // 5c 5C \
- return new TypeError(
- 'Path must not include encoded \\ or / characters');
+ return new errors.TypeError('ERR_INVALID_FILE_URL_PATH',
+ 'not include encoded \\ or / characters');
}
}
}
@@ -1319,7 +1322,7 @@ function getPathFromURLWin32(url) {
var sep = pathname[2];
if (letter < 97 || letter > 122 || // a..z A..Z
(sep !== ':')) {
- return new TypeError('File URLs must specify absolute paths');
+ return new errors.TypeError('ERR_INVALID_FILE_URL_PATH', 'be absolute');
}
return pathname.slice(1);
}
@@ -1327,16 +1330,16 @@ function getPathFromURLWin32(url) {
function getPathFromURLPosix(url) {
if (url.hostname !== '') {
- return new TypeError(
- `File URLs on ${os.platform()} must use hostname 'localhost'` +
- ' or not specify any hostname');
+ return new errors.TypeError('ERR_INVALID_FILE_URL_HOST',
+ `be "localhost" or empty on ${platform}`);
}
var pathname = url.pathname;
for (var n = 0; n < pathname.length; n++) {
if (pathname[n] === '%') {
var third = pathname.codePointAt(n + 2) | 0x20;
if (pathname[n + 1] === '2' && third === 102) {
- return new TypeError('Path must not include encoded / characters');
+ return new errors.TypeError('ERR_INVALID_FILE_URL_PATH',
+ 'not include encoded / characters');
}
}
}
@@ -1349,7 +1352,7 @@ function getPathFromURL(path) {
return path;
}
if (path.protocol !== 'file:')
- return new TypeError('Only `file:` URLs are supported');
+ return new errors.TypeError('ERR_INVALID_URL_SCHEME', 'file');
return isWindows ? getPathFromURLWin32(path) : getPathFromURLPosix(path);
}
diff --git a/test/common.js b/test/common.js
index 6fe2d4520f6a08..3a49a53a11b14b 100644
--- a/test/common.js
+++ b/test/common.js
@@ -617,7 +617,9 @@ exports.WPT = {
assert_false: (value, message) => assert.strictEqual(value, false, message),
assert_throws: (code, func, desc) => {
assert.throws(func, (err) => {
- return typeof err === 'object' && 'name' in err && err.name === code.name;
+ return typeof err === 'object' &&
+ 'name' in err &&
+ err.name.startsWith(code.name);
}, desc);
},
assert_array_equals: assert.deepStrictEqual,
diff --git a/test/parallel/test-fs-whatwg-url.js b/test/parallel/test-fs-whatwg-url.js
index 7a94fd68d7e4fa..ff2ee641e12a7e 100644
--- a/test/parallel/test-fs-whatwg-url.js
+++ b/test/parallel/test-fs-whatwg-url.js
@@ -30,9 +30,11 @@ fs.readFile(url, common.mustCall((err, data) => {
// Check that using a non file:// URL reports an error
const httpUrl = new URL('http://example.org');
fs.readFile(httpUrl, common.mustCall((err) => {
- assert(err);
- assert.strictEqual(err.message,
- 'Only `file:` URLs are supported');
+ common.expectsError({
+ code: 'ERR_INVALID_URL_SCHEME',
+ type: TypeError,
+ message: 'The URL must be of scheme file'
+ })(err);
}));
// pct-encoded characters in the path will be decoded and checked
@@ -46,25 +48,30 @@ if (common.isWindows) {
// encoded back and forward slashes are not permitted on windows
['%2f', '%2F', '%5c', '%5C'].forEach((i) => {
fs.readFile(new URL(`file:///c:/tmp/${i}`), common.mustCall((err) => {
- assert(err);
- assert.strictEqual(err.message,
- 'Path must not include encoded \\ or / characters');
+ common.expectsError({
+ code: 'ERR_INVALID_FILE_URL_PATH',
+ type: TypeError,
+ message: 'File URL path must not include encoded \\ or / characters'
+ })(err);
}));
});
} else {
// encoded forward slashes are not permitted on other platforms
['%2f', '%2F'].forEach((i) => {
fs.readFile(new URL(`file:///c:/tmp/${i}`), common.mustCall((err) => {
- assert(err);
- assert.strictEqual(err.message,
- 'Path must not include encoded / characters');
+ common.expectsError({
+ code: 'ERR_INVALID_FILE_URL_PATH',
+ type: TypeError,
+ message: 'File URL path must not include encoded / characters'
+ })(err);
}));
});
fs.readFile(new URL('file://hostname/a/b/c'), common.mustCall((err) => {
- assert(err);
- assert.strictEqual(err.message,
- `File URLs on ${os.platform()} must use ` +
- 'hostname \'localhost\' or not specify any hostname');
+ common.expectsError({
+ code: 'ERR_INVALID_FILE_URL_HOST',
+ type: TypeError,
+ message: `File URL host must be "localhost" or empty on ${os.platform()}`
+ })(err);
}));
}
diff --git a/test/parallel/test-internal-errors.js b/test/parallel/test-internal-errors.js
index a673fdf8a4caf4..dd4f02c1f758bf 100644
--- a/test/parallel/test-internal-errors.js
+++ b/test/parallel/test-internal-errors.js
@@ -150,3 +150,29 @@ assert.strictEqual(errors.message('ERR_INVALID_ARG_TYPE',
assert.strictEqual(errors.message('ERR_INVALID_ARG_TYPE',
['a', 'b', null]),
'The "a" argument must be of type b. Received type null');
+
+// Test ERR_INVALID_URL_SCHEME
+assert.strictEqual(errors.message('ERR_INVALID_URL_SCHEME', ['file']),
+ 'The URL must be of scheme file');
+assert.strictEqual(errors.message('ERR_INVALID_URL_SCHEME', [['file']]),
+ 'The URL must be of scheme file');
+assert.strictEqual(errors.message('ERR_INVALID_URL_SCHEME', [['http', 'ftp']]),
+ 'The URL must be one of scheme http or ftp');
+assert.strictEqual(errors.message('ERR_INVALID_URL_SCHEME', [['a', 'b', 'c']]),
+ 'The URL must be one of scheme a, b, or c');
+assert.throws(
+ () => errors.message('ERR_INVALID_URL_SCHEME', [[]]),
+ /^AssertionError: At least one expected value needs to be specified$/
+);
+
+// Test ERR_MISSING_ARGS
+assert.strictEqual(errors.message('ERR_MISSING_ARGS', ['name']),
+ 'The "name" argument must be specified');
+assert.strictEqual(errors.message('ERR_MISSING_ARGS', ['name', 'value']),
+ 'The "name" and "value" arguments must be specified');
+assert.strictEqual(errors.message('ERR_MISSING_ARGS', ['a', 'b', 'c']),
+ 'The "a", "b", and "c" arguments must be specified');
+assert.throws(
+ () => errors.message('ERR_MISSING_ARGS'),
+ /^AssertionError: At least one arg needs to be specified$/
+);
diff --git a/test/parallel/test-url-format-whatwg.js b/test/parallel/test-url-format-whatwg.js
index 507d3f8419d73e..f9e5691ae5cc04 100644
--- a/test/parallel/test-url-format-whatwg.js
+++ b/test/parallel/test-url-format-whatwg.js
@@ -1,6 +1,6 @@
'use strict';
-require('../common');
+const common = require('../common');
const assert = require('assert');
const url = require('url');
const URL = url.URL;
@@ -17,11 +17,17 @@ assert.strictEqual(
'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c'
);
-const errreg = /^TypeError: options must be an object$/;
-assert.throws(() => url.format(myURL, true), errreg);
-assert.throws(() => url.format(myURL, 1), errreg);
-assert.throws(() => url.format(myURL, 'test'), errreg);
-assert.throws(() => url.format(myURL, Infinity), errreg);
+{
+ const expectedErr = common.expectsError({
+ code: 'ERR_INVALID_ARG_TYPE',
+ type: TypeError,
+ message: 'The "options" argument must be of type object'
+ });
+ assert.throws(() => url.format(myURL, true), expectedErr);
+ assert.throws(() => url.format(myURL, 1), expectedErr);
+ assert.throws(() => url.format(myURL, 'test'), expectedErr);
+ assert.throws(() => url.format(myURL, Infinity), expectedErr);
+}
// Any falsy value other than undefined will be treated as false.
// Any truthy value will be treated as true.
diff --git a/test/parallel/test-whatwg-url-domainto.js b/test/parallel/test-whatwg-url-domainto.js
index 70b32c8dce279c..13ff9968705b98 100644
--- a/test/parallel/test-whatwg-url-domainto.js
+++ b/test/parallel/test-whatwg-url-domainto.js
@@ -13,10 +13,10 @@ const { domainToASCII, domainToUnicode } = require('url');
const tests = require('../fixtures/url-idna.js');
{
- assert.throws(() => domainToASCII(),
- /^TypeError: "domain" argument must be specified$/);
- assert.throws(() => domainToUnicode(),
- /^TypeError: "domain" argument must be specified$/);
+ const expectedError = common.expectsError(
+ { code: 'ERR_MISSING_ARGS', type: TypeError });
+ assert.throws(() => domainToASCII(), expectedError);
+ assert.throws(() => domainToUnicode(), expectedError);
assert.strictEqual(domainToASCII(undefined), 'undefined');
assert.strictEqual(domainToUnicode(undefined), 'undefined');
}
diff --git a/test/parallel/test-whatwg-url-parsing.js b/test/parallel/test-whatwg-url-parsing.js
index c82461c25e4383..0e8f3b6d77cb56 100644
--- a/test/parallel/test-whatwg-url-parsing.js
+++ b/test/parallel/test-whatwg-url-parsing.js
@@ -26,12 +26,18 @@ const failureTests = tests.filter((test) => test.failure).concat([
{ input: common.noop }
]);
+const expectedError = common.expectsError(
+ { code: 'ERR_INVALID_URL', type: TypeError });
+
for (const test of failureTests) {
assert.throws(
() => new URL(test.input, test.base),
(error) => {
+ if (!expectedError(error))
+ return false;
+
// The input could be processed, so we don't do strict matching here
- const match = (error + '').match(/^TypeError: Invalid URL: (.*)$/);
+ const match = (error + '').match(/Invalid URL: (.*)$/);
if (!match) {
return false;
}
diff --git a/test/parallel/test-whatwg-url-searchparams-append.js b/test/parallel/test-whatwg-url-searchparams-append.js
index ff4a568c303668..de59e9e1429fb2 100644
--- a/test/parallel/test-whatwg-url-searchparams-append.js
+++ b/test/parallel/test-whatwg-url-searchparams-append.js
@@ -53,10 +53,18 @@ test(function() {
const params = new URLSearchParams();
assert.throws(() => {
params.append.call(undefined);
- }, /^TypeError: Value of `this` is not a URLSearchParams$/);
+ }, common.expectsError({
+ code: 'ERR_INVALID_THIS',
+ type: TypeError,
+ message: 'Value of this must be of type URLSearchParams'
+ }));
assert.throws(() => {
- params.set('a');
- }, /^TypeError: "name" and "value" arguments must be specified$/);
+ params.append('a');
+ }, common.expectsError({
+ code: 'ERR_MISSING_ARGS',
+ type: TypeError,
+ message: 'The "name" and "value" arguments must be specified'
+ }));
const obj = {
toString() { throw new Error('toString'); },
diff --git a/test/parallel/test-whatwg-url-searchparams-constructor.js b/test/parallel/test-whatwg-url-searchparams-constructor.js
index da459fe99c7fb8..67ee28602b2af6 100644
--- a/test/parallel/test-whatwg-url-searchparams-constructor.js
+++ b/test/parallel/test-whatwg-url-searchparams-constructor.js
@@ -188,24 +188,31 @@ test(() => {
}
{
+ const iterableError = common.expectsError({
+ code: 'ERR_ARG_NOT_ITERABLE',
+ type: TypeError,
+ message: 'Query pairs must be iterable'
+ });
+ const tupleError = common.expectsError({
+ code: 'ERR_INVALID_TUPLE',
+ type: TypeError,
+ message: 'Each query pair must be an iterable name/value tuple'
+ });
+
let params;
// URLSearchParams constructor, undefined and null as argument
params = new URLSearchParams(undefined);
assert.strictEqual(params.toString(), '');
params = new URLSearchParams(null);
assert.strictEqual(params.toString(), '');
- assert.throws(() => new URLSearchParams([[1]]),
- /^TypeError: Each query pair must be a name\/value tuple$/);
- assert.throws(() => new URLSearchParams([[1, 2, 3]]),
- /^TypeError: Each query pair must be a name\/value tuple$/);
+ assert.throws(() => new URLSearchParams([[1]]), tupleError);
+ assert.throws(() => new URLSearchParams([[1, 2, 3]]), tupleError);
assert.throws(() => new URLSearchParams({ [Symbol.iterator]: 42 }),
- /^TypeError: Query pairs must be iterable$/);
- assert.throws(() => new URLSearchParams([{}]),
- /^TypeError: Each query pair must be iterable$/);
- assert.throws(() => new URLSearchParams(['a']),
- /^TypeError: Each query pair must be iterable$/);
+ iterableError);
+ assert.throws(() => new URLSearchParams([{}]), tupleError);
+ assert.throws(() => new URLSearchParams(['a']), tupleError);
assert.throws(() => new URLSearchParams([{ [Symbol.iterator]: 42 }]),
- /^TypeError: Each query pair must be iterable$/);
+ tupleError);
}
{
diff --git a/test/parallel/test-whatwg-url-searchparams-delete.js b/test/parallel/test-whatwg-url-searchparams-delete.js
index 589fbc2f8698b5..7484de7a48ce7c 100644
--- a/test/parallel/test-whatwg-url-searchparams-delete.js
+++ b/test/parallel/test-whatwg-url-searchparams-delete.js
@@ -47,10 +47,18 @@ test(function() {
const params = new URLSearchParams();
assert.throws(() => {
params.delete.call(undefined);
- }, /^TypeError: Value of `this` is not a URLSearchParams$/);
+ }, common.expectsError({
+ code: 'ERR_INVALID_THIS',
+ type: TypeError,
+ message: 'Value of this must be of type URLSearchParams'
+ }));
assert.throws(() => {
params.delete();
- }, /^TypeError: "name" argument must be specified$/);
+ }, common.expectsError({
+ code: 'ERR_MISSING_ARGS',
+ type: TypeError,
+ message: 'The "name" argument must be specified'
+ }));
const obj = {
toString() { throw new Error('toString'); },
diff --git a/test/parallel/test-whatwg-url-searchparams-entries.js b/test/parallel/test-whatwg-url-searchparams-entries.js
index c8b8d129b01ad9..7c23269ddcb36d 100644
--- a/test/parallel/test-whatwg-url-searchparams-entries.js
+++ b/test/parallel/test-whatwg-url-searchparams-entries.js
@@ -1,6 +1,6 @@
'use strict';
-require('../common');
+const common = require('../common');
const assert = require('assert');
const URLSearchParams = require('url').URLSearchParams;
@@ -28,7 +28,15 @@ assert.deepStrictEqual(entries.next(), {
assert.throws(() => {
entries.next.call(undefined);
-}, /^TypeError: Value of `this` is not a URLSearchParamsIterator$/);
+}, common.expectsError({
+ code: 'ERR_INVALID_THIS',
+ type: TypeError,
+ message: 'Value of this must be of type URLSearchParamsIterator'
+}));
assert.throws(() => {
params.entries.call(undefined);
-}, /^TypeError: Value of `this` is not a URLSearchParams$/);
+}, common.expectsError({
+ code: 'ERR_INVALID_THIS',
+ type: TypeError,
+ message: 'Value of this must be of type URLSearchParams'
+}));
diff --git a/test/parallel/test-whatwg-url-searchparams-foreach.js b/test/parallel/test-whatwg-url-searchparams-foreach.js
index 9181371ae51c89..3a95d04b8df054 100644
--- a/test/parallel/test-whatwg-url-searchparams-foreach.js
+++ b/test/parallel/test-whatwg-url-searchparams-foreach.js
@@ -50,5 +50,9 @@ test(function() {
const params = new URLSearchParams();
assert.throws(() => {
params.forEach.call(undefined);
- }, /^TypeError: Value of `this` is not a URLSearchParams$/);
+ }, common.expectsError({
+ code: 'ERR_INVALID_THIS',
+ type: TypeError,
+ message: 'Value of this must be of type URLSearchParams'
+ }));
}
diff --git a/test/parallel/test-whatwg-url-searchparams-get.js b/test/parallel/test-whatwg-url-searchparams-get.js
index 5e81be4f32cc1d..a743f6d94cc961 100644
--- a/test/parallel/test-whatwg-url-searchparams-get.js
+++ b/test/parallel/test-whatwg-url-searchparams-get.js
@@ -38,10 +38,18 @@ test(function() {
const params = new URLSearchParams();
assert.throws(() => {
params.get.call(undefined);
- }, /^TypeError: Value of `this` is not a URLSearchParams$/);
+ }, common.expectsError({
+ code: 'ERR_INVALID_THIS',
+ type: TypeError,
+ message: 'Value of this must be of type URLSearchParams'
+ }));
assert.throws(() => {
params.get();
- }, /^TypeError: "name" argument must be specified$/);
+ }, common.expectsError({
+ code: 'ERR_MISSING_ARGS',
+ type: TypeError,
+ message: 'The "name" argument must be specified'
+ }));
const obj = {
toString() { throw new Error('toString'); },
diff --git a/test/parallel/test-whatwg-url-searchparams-getall.js b/test/parallel/test-whatwg-url-searchparams-getall.js
index f80f45d5427e77..d4617164d34222 100644
--- a/test/parallel/test-whatwg-url-searchparams-getall.js
+++ b/test/parallel/test-whatwg-url-searchparams-getall.js
@@ -42,10 +42,18 @@ test(function() {
const params = new URLSearchParams();
assert.throws(() => {
params.getAll.call(undefined);
- }, /^TypeError: Value of `this` is not a URLSearchParams$/);
+ }, common.expectsError({
+ code: 'ERR_INVALID_THIS',
+ type: TypeError,
+ message: 'Value of this must be of type URLSearchParams'
+ }));
assert.throws(() => {
params.getAll();
- }, /^TypeError: "name" argument must be specified$/);
+ }, common.expectsError({
+ code: 'ERR_MISSING_ARGS',
+ type: TypeError,
+ message: 'The "name" argument must be specified'
+ }));
const obj = {
toString() { throw new Error('toString'); },
diff --git a/test/parallel/test-whatwg-url-searchparams-has.js b/test/parallel/test-whatwg-url-searchparams-has.js
index f2696063b998a1..b6cf4e7c754d01 100644
--- a/test/parallel/test-whatwg-url-searchparams-has.js
+++ b/test/parallel/test-whatwg-url-searchparams-has.js
@@ -41,10 +41,18 @@ test(function() {
const params = new URLSearchParams();
assert.throws(() => {
params.has.call(undefined);
- }, /^TypeError: Value of `this` is not a URLSearchParams$/);
+ }, common.expectsError({
+ code: 'ERR_INVALID_THIS',
+ type: TypeError,
+ message: 'Value of this must be of type URLSearchParams'
+ }));
assert.throws(() => {
params.has();
- }, /^TypeError: "name" argument must be specified$/);
+ }, common.expectsError({
+ code: 'ERR_MISSING_ARGS',
+ type: TypeError,
+ message: 'The "name" argument must be specified'
+ }));
const obj = {
toString() { throw new Error('toString'); },
diff --git a/test/parallel/test-whatwg-url-searchparams-keys.js b/test/parallel/test-whatwg-url-searchparams-keys.js
index 6942b152cd78e8..5f053307ed8049 100644
--- a/test/parallel/test-whatwg-url-searchparams-keys.js
+++ b/test/parallel/test-whatwg-url-searchparams-keys.js
@@ -1,6 +1,6 @@
'use strict';
-require('../common');
+const common = require('../common');
const assert = require('assert');
const URLSearchParams = require('url').URLSearchParams;
@@ -29,7 +29,15 @@ assert.deepStrictEqual(keys.next(), {
assert.throws(() => {
keys.next.call(undefined);
-}, /^TypeError: Value of `this` is not a URLSearchParamsIterator$/);
+}, common.expectsError({
+ code: 'ERR_INVALID_THIS',
+ type: TypeError,
+ message: 'Value of this must be of type URLSearchParamsIterator'
+}));
assert.throws(() => {
params.keys.call(undefined);
-}, /^TypeError: Value of `this` is not a URLSearchParams$/);
+}, common.expectsError({
+ code: 'ERR_INVALID_THIS',
+ type: TypeError,
+ message: 'Value of this must be of type URLSearchParams'
+}));
diff --git a/test/parallel/test-whatwg-url-searchparams-set.js b/test/parallel/test-whatwg-url-searchparams-set.js
index acd62955d22a44..afd289927d1944 100644
--- a/test/parallel/test-whatwg-url-searchparams-set.js
+++ b/test/parallel/test-whatwg-url-searchparams-set.js
@@ -39,10 +39,18 @@ test(function() {
const params = new URLSearchParams();
assert.throws(() => {
params.set.call(undefined);
- }, /^TypeError: Value of `this` is not a URLSearchParams$/);
+ }, common.expectsError({
+ code: 'ERR_INVALID_THIS',
+ type: TypeError,
+ message: 'Value of this must be of type URLSearchParams'
+ }));
assert.throws(() => {
params.set('a');
- }, /^TypeError: "name" and "value" arguments must be specified$/);
+ }, common.expectsError({
+ code: 'ERR_MISSING_ARGS',
+ type: TypeError,
+ message: 'The "name" and "value" arguments must be specified'
+ }));
const obj = {
toString() { throw new Error('toString'); },
diff --git a/test/parallel/test-whatwg-url-searchparams-stringifier.js b/test/parallel/test-whatwg-url-searchparams-stringifier.js
index ac09979e027b7c..ebcdd838bedfb5 100644
--- a/test/parallel/test-whatwg-url-searchparams-stringifier.js
+++ b/test/parallel/test-whatwg-url-searchparams-stringifier.js
@@ -127,5 +127,9 @@ test(function() {
const params = new URLSearchParams();
assert.throws(() => {
params.toString.call(undefined);
- }, /^TypeError: Value of `this` is not a URLSearchParams$/);
+ }, common.expectsError({
+ code: 'ERR_INVALID_THIS',
+ type: TypeError,
+ message: 'Value of this must be of type URLSearchParams'
+ }));
}
diff --git a/test/parallel/test-whatwg-url-searchparams-values.js b/test/parallel/test-whatwg-url-searchparams-values.js
index eb6fa05daf3496..8558ada06f6707 100644
--- a/test/parallel/test-whatwg-url-searchparams-values.js
+++ b/test/parallel/test-whatwg-url-searchparams-values.js
@@ -1,6 +1,6 @@
'use strict';
-require('../common');
+const common = require('../common');
const assert = require('assert');
const URLSearchParams = require('url').URLSearchParams;
@@ -29,7 +29,15 @@ assert.deepStrictEqual(values.next(), {
assert.throws(() => {
values.next.call(undefined);
-}, /^TypeError: Value of `this` is not a URLSearchParamsIterator$/);
+}, common.expectsError({
+ code: 'ERR_INVALID_THIS',
+ type: TypeError,
+ message: 'Value of this must be of type URLSearchParamsIterator'
+}));
assert.throws(() => {
params.values.call(undefined);
-}, /^TypeError: Value of `this` is not a URLSearchParams$/);
+}, common.expectsError({
+ code: 'ERR_INVALID_THIS',
+ type: TypeError,
+ message: 'Value of this must be of type URLSearchParams'
+}));
diff --git a/test/parallel/test-whatwg-url-searchparams.js b/test/parallel/test-whatwg-url-searchparams.js
index c7acb7d909d98c..5bb9cf407dc1e9 100644
--- a/test/parallel/test-whatwg-url-searchparams.js
+++ b/test/parallel/test-whatwg-url-searchparams.js
@@ -71,10 +71,15 @@ sp.forEach(function(val, key, obj) {
sp.forEach(function() {
assert.strictEqual(this, m);
}, m);
-assert.throws(() => sp.forEach(),
- /^TypeError: "callback" argument must be a function$/);
-assert.throws(() => sp.forEach(1),
- /^TypeError: "callback" argument must be a function$/);
+
+{
+ const callbackErr = common.expectsError({
+ code: 'ERR_INVALID_CALLBACK',
+ type: TypeError
+ });
+ assert.throws(() => sp.forEach(), callbackErr);
+ assert.throws(() => sp.forEach(1), callbackErr);
+}
m.search = '?a=a&b=b';
assert.strictEqual(sp.toString(), 'a=a&b=b');