diff --git a/src/js/node/zlib.ts b/src/js/node/zlib.ts index 22059bbb0907..30380aa8d68f 100644 --- a/src/js/node/zlib.ts +++ b/src/js/node/zlib.ts @@ -114,7 +114,7 @@ function zlibBufferSync(engine, buffer) { if (isAnyArrayBuffer(buffer)) { buffer = Buffer.from(buffer); } else { - throw $ERR_INVALID_ARG_TYPE("buffer", "string, Buffer, TypedArray, DataView, or ArrayBuffer", buffer); + throw $ERR_INVALID_ARG_TYPE("buffer", ["string", "Buffer", "TypedArray", "DataView", "ArrayBuffer"], buffer); } } buffer = processChunkSync(engine, buffer, engine._finishFlushFlag); diff --git a/src/jsc/JSGlobalObject.rs b/src/jsc/JSGlobalObject.rs index 06966fbabd17..7b462c8b8ada 100644 --- a/src/jsc/JSGlobalObject.rs +++ b/src/jsc/JSGlobalObject.rs @@ -542,9 +542,47 @@ impl JSGlobalObject { .throw() } - /// "The {argname} argument must be of type {typename}. Received {value}" - /// - /// Accepts `&str`, `&[u8]`, or `b"..."` for `argname`/`typename`. + /// Renders Node's `ERR_INVALID_ARG_TYPE` message via the shared C++ formatter + /// so Rust and C++ agree on `argument`/`property` and `of type`/`an instance of`. + /// https://github.com/nodejs/node/blob/main/lib/internal/errors.js + pub fn format_invalid_argument_type( + global: &Self, + argname: &[u8], + expected_types: &[&[u8]], + value: JSValue, + ) -> JsResult { + crate::top_scope!(scope, global); + let types: Vec = expected_types + .iter() + .map(|t| BunString::borrow_utf8(t)) + .collect(); + // SAFETY: `types` outlives the call; the C++ side copies each entry into + // a `WTF::String` before returning. + let str = OwnedString::new(unsafe { + Bun__ErrorCode__formatInvalidArgType( + global, + BunString::borrow_utf8(argname), + types.as_ptr(), + types.len(), + value, + ) + }); + scope.return_if_exception()?; + Ok(str) + } + + /// Node renders `"" argument` for a plain name and `"" property` + /// for a dotted one. Returns a +1-ref'd string wrapped in [`OwnedString`]. + /// https://github.com/nodejs/node/blob/v26.3.0/lib/internal/errors.js#L1394 + pub fn format_parameter_name(argname: &[u8]) -> OwnedString { + OwnedString::new(Bun__ErrorCode__formatParameterName(BunString::borrow_utf8( + argname, + ))) + } + + /// "The {argname} argument must be of type {typename}. Received {value}". + /// `typename` is used verbatim; for a list of type/class names use + /// [`Self::throw_invalid_argument_type_list`] to get Node's grouping. pub fn throw_invalid_argument_type_value( &self, argname: impl AsRef<[u8]>, @@ -558,8 +596,8 @@ impl JSGlobalObject { self.err( JscError::INVALID_ARG_TYPE, format_args!( - "The \"{}\" argument must be of type {}. Received {}", - bstr::BStr::new(argname.as_ref()), + "The {} must be of type {}. Received {}", + Self::format_parameter_name(argname.as_ref()), bstr::BStr::new(typename.as_ref()), actual_string_value ), @@ -567,6 +605,25 @@ impl JSGlobalObject { .throw() } + /// `ERR_INVALID_ARG_TYPE` with several accepted types, rendered the way + /// Node renders an array of expected types (`of type string or an instance + /// of Buffer or URL`). + pub fn throw_invalid_argument_type_list( + &self, + argname: impl AsRef<[u8]>, + expected_types: &[&[u8]], + value: JSValue, + ) -> JsError { + let message = + match Self::format_invalid_argument_type(self, argname.as_ref(), expected_types, value) + { + Ok(s) => s, + Err(e) => return e, + }; + self.err(JscError::INVALID_ARG_TYPE, format_args!("{}", message)) + .throw() + } + pub fn throw_invalid_argument_type_value2( &self, argname: impl AsRef<[u8]>, @@ -580,8 +637,8 @@ impl JSGlobalObject { self.err( JscError::INVALID_ARG_TYPE, format_args!( - "The \"{}\" argument must be {}. Received {}", - bstr::BStr::new(argname.as_ref()), + "The {} must be {}. Received {}", + Self::format_parameter_name(argname.as_ref()), bstr::BStr::new(typename.as_ref()), actual_string_value ), @@ -615,29 +672,6 @@ impl JSGlobalObject { .throw() } - /// "The argument must be one of type . Received " - pub fn throw_invalid_argument_type_value_one_of( - &self, - argname: impl AsRef<[u8]>, - typename: impl AsRef<[u8]>, - value: JSValue, - ) -> JsError { - let actual_string_value = match Self::determine_specific_type(self, value) { - Ok(s) => s, - Err(e) => return e, - }; - self.err( - JscError::INVALID_ARG_TYPE, - format_args!( - "The \"{}\" argument must be one of type {}. Received {}", - bstr::BStr::new(argname.as_ref()), - bstr::BStr::new(typename.as_ref()), - actual_string_value - ), - ) - .throw() - } - pub fn throw_invalid_property_type_value( &self, field: &[u8], @@ -1498,6 +1532,19 @@ unsafe extern "C" { value: JSValue, ) -> BunString; + safe fn Bun__ErrorCode__formatParameterName(arg_name: BunString) -> BunString; + + // `expected_types` is a `(ptr, len)` pair the C++ side dereferences, so this + // one stays `unsafe`; `JSGlobalObject::format_invalid_argument_type` is the + // only caller and passes a live slice. + fn Bun__ErrorCode__formatInvalidArgType( + global: &JSGlobalObject, + arg_name: BunString, + expected_types: *const BunString, + expected_types_length: usize, + value: JSValue, + ) -> BunString; + // safe: `JSGlobalObject` is an opaque `UnsafeCell`-backed ZST handle (`&` is // ABI-identical to non-null `*const`); `Option<&BunString>` is ABI-identical // to a nullable `*const BunString` via the guaranteed null-pointer diff --git a/src/jsc/bindings/ErrorCode.cpp b/src/jsc/bindings/ErrorCode.cpp index 7674a579d33d..fc45043bc767 100644 --- a/src/jsc/bindings/ErrorCode.cpp +++ b/src/jsc/bindings/ErrorCode.cpp @@ -700,7 +700,7 @@ static bool isClassName(const WTF::String& type) // grouped into primitive type names ("of type ..."), class names ("an // instance of ..."), and everything else. // https://github.com/nodejs/node/blob/v26.3.0/lib/internal/errors.js#L1404 -WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, const StringView& arg_name, ArgList expected_types, JSValue actual_value) +static WTF::String formatInvalidArgType(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, const StringView& arg_name, const WTF::Vector& expected_types, JSValue actual_value) { WTF::StringBuilder result; @@ -712,12 +712,7 @@ WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* gl WTF::Vector instances; WTF::Vector other; - for (unsigned i = 0, length = expected_types.size(); i < length; i++) { - auto* str = expected_types.at(i).toString(globalObject); - RETURN_IF_EXCEPTION(scope, {}); - auto view = str->view(globalObject); - RETURN_IF_EXCEPTION(scope, {}); - WTF::String value = view->toString(); + for (const auto& value : expected_types) { if (isPrimitiveTypeName(value)) types.append(value.convertToASCIILowercase()); else if (isClassName(value)) @@ -768,6 +763,47 @@ WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* gl return result.toString(); } +WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, const StringView& arg_name, ArgList expected_types, JSValue actual_value) +{ + WTF::Vector types; + types.reserveInitialCapacity(expected_types.size()); + for (unsigned i = 0, length = expected_types.size(); i < length; i++) { + auto* str = expected_types.at(i).toString(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + auto view = str->view(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + types.append(view->toString()); + } + RELEASE_AND_RETURN(scope, formatInvalidArgType(scope, globalObject, arg_name, types, actual_value)); +} + +// Renders the "" argument / "" property prefix Node's +// ERR_INVALID_ARG_TYPE uses, so Rust-side messages pick "property" for dotted +// names the same way the C++ ones do. +extern "C" BunString Bun__ErrorCode__formatParameterName(BunString argName) +{ + WTF::StringBuilder result; + auto argNameString = argName.toWTFString(); + addParameter(result, argNameString); + return Bun::toStringRef(result.toString()); +} + +// Rust entry point for formatInvalidArgType so both sides share one renderer. +// https://github.com/nodejs/node/blob/main/lib/internal/errors.js +extern "C" BunString Bun__ErrorCode__formatInvalidArgType(JSC::JSGlobalObject* globalObject, BunString argName, const BunString* expectedTypes, size_t expectedTypesLength, EncodedJSValue value) +{ + auto scope = DECLARE_THROW_SCOPE(JSC::getVM(globalObject)); + WTF::Vector types; + types.reserveInitialCapacity(expectedTypesLength); + for (size_t i = 0; i < expectedTypesLength; i++) { + types.append(expectedTypes[i].toWTFString()); + } + auto argNameString = argName.toWTFString(); + auto message = formatInvalidArgType(scope, globalObject, argNameString, types, JSValue::decode(value)); + RETURN_IF_EXCEPTION(scope, Zig::BunStringEmpty); + return Bun::toStringRef(message); +} + WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue val_arg_name, JSValue val_expected_type, JSValue val_actual_value) { auto* arg_name_str = val_arg_name.toString(globalObject); diff --git a/src/jsc/bindings/JSDOMExceptionHandling.cpp b/src/jsc/bindings/JSDOMExceptionHandling.cpp index 9db6f0f283de..5333328f00c3 100644 --- a/src/jsc/bindings/JSDOMExceptionHandling.cpp +++ b/src/jsc/bindings/JSDOMExceptionHandling.cpp @@ -269,9 +269,13 @@ JSC::EncodedJSValue rejectPromiseWithGetterTypeError(JSC::JSGlobalObject& lexica return createRejectedPromiseWithTypeError(lexicalGlobalObject, JSC::makeDOMAttributeGetterTypeErrorMessage(classInfo->className, String(attributeName.uid())), RejectedPromiseWithTypeErrorCause::NativeGetter); } +// Node reports ERR_INVALID_THIS as `Value of "this" must be of type X`, without +// naming the method. +// https://github.com/nodejs/node/blob/v26.3.0/lib/internal/errors.js#L1585 String makeThisTypeErrorMessage(ASCIILiteral interfaceName, ASCIILiteral functionName) { - return makeString("Can only call "_s, interfaceName, '.', functionName, " on instances of "_s, interfaceName); + UNUSED_PARAM(functionName); + return makeString("Value of \"this\" must be of type "_s, interfaceName); } EncodedJSValue throwThisTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, ASCIILiteral interfaceName, ASCIILiteral attributeName) diff --git a/src/jsc/bindings/webcore/JSDOMIterator.h b/src/jsc/bindings/webcore/JSDOMIterator.h index dbd1ce44e042..8bf02a072e9f 100644 --- a/src/jsc/bindings/webcore/JSDOMIterator.h +++ b/src/jsc/bindings/webcore/JSDOMIterator.h @@ -261,7 +261,9 @@ JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSDOMIteratorPrototype>(callFrame->thisValue()); if (!iterator) { - return Bun::throwError(globalObject, scope, Bun::ErrorCode::ERR_INVALID_THIS, "Cannot call next() on a non-Iterator object"_s); + // Node names the iterator interface, e.g. "URLSearchParamsIterator". + // https://github.com/nodejs/node/blob/v26.3.0/lib/internal/errors.js#L1585 + return Bun::throwError(globalObject, scope, Bun::ErrorCode::ERR_INVALID_THIS, makeString("Value of \"this\" must be of type "_s, JSWrapper::info()->className, "Iterator"_s)); } RELEASE_AND_RETURN(scope, JSC::JSValue::encode(iterator->next(*globalObject))); diff --git a/src/jsc/bindings/webcore/JSURLSearchParams.cpp b/src/jsc/bindings/webcore/JSURLSearchParams.cpp index c4260c01543e..40a175bcc5db 100644 --- a/src/jsc/bindings/webcore/JSURLSearchParams.cpp +++ b/src/jsc/bindings/webcore/JSURLSearchParams.cpp @@ -24,6 +24,7 @@ #include "ExtendedDOMClientIsoSubspaces.h" #include "ExtendedDOMIsoSubspaces.h" #include "IDLTypes.h" +#include "ErrorCode.h" #include "JSDOMBinding.h" #include "JSDOMConstructor.h" #include "JSDOMConvertBase.h" @@ -388,7 +389,7 @@ static inline JSC::EncodedJSValue jsURLSearchParamsPrototypeFunction_appendBody( UNUSED_PARAM(callFrame); auto& impl = castedThis->wrapped(); if (callFrame->argumentCount() < 2) [[unlikely]] - return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); + return Bun::ERR::MISSING_ARGS(throwScope, lexicalGlobalObject, "The \"name\" and \"value\" arguments must be specified"_s); EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); auto name = convert(*lexicalGlobalObject, argument0.value()); RETURN_IF_EXCEPTION(throwScope, {}); @@ -411,7 +412,7 @@ static inline JSC::EncodedJSValue jsURLSearchParamsPrototypeFunction_deleteBody( UNUSED_PARAM(callFrame); auto& impl = castedThis->wrapped(); if (callFrame->argumentCount() < 1) [[unlikely]] - return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); + return Bun::ERR::MISSING_ARGS(throwScope, lexicalGlobalObject, "The \"name\" argument must be specified"_s); EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); auto name = convert(*lexicalGlobalObject, argument0.value()); RETURN_IF_EXCEPTION(throwScope, {}); @@ -439,7 +440,7 @@ static inline JSC::EncodedJSValue jsURLSearchParamsPrototypeFunction_getBody(JSC UNUSED_PARAM(callFrame); auto& impl = castedThis->wrapped(); if (callFrame->argumentCount() < 1) [[unlikely]] - return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); + return Bun::ERR::MISSING_ARGS(throwScope, lexicalGlobalObject, "The \"name\" argument must be specified"_s); EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); auto name = convert(*lexicalGlobalObject, argument0.value()); RETURN_IF_EXCEPTION(throwScope, {}); @@ -459,7 +460,7 @@ static inline JSC::EncodedJSValue jsURLSearchParamsPrototypeFunction_getAllBody( UNUSED_PARAM(callFrame); auto& impl = castedThis->wrapped(); if (callFrame->argumentCount() < 1) [[unlikely]] - return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); + return Bun::ERR::MISSING_ARGS(throwScope, lexicalGlobalObject, "The \"name\" argument must be specified"_s); EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); auto name = convert(*lexicalGlobalObject, argument0.value()); RETURN_IF_EXCEPTION(throwScope, {}); @@ -479,7 +480,7 @@ static inline JSC::EncodedJSValue jsURLSearchParamsPrototypeFunction_hasBody(JSC UNUSED_PARAM(callFrame); auto& impl = castedThis->wrapped(); if (callFrame->argumentCount() < 1) [[unlikely]] - return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); + return Bun::ERR::MISSING_ARGS(throwScope, lexicalGlobalObject, "The \"name\" argument must be specified"_s); EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); auto name = convert(*lexicalGlobalObject, argument0.value()); RETURN_IF_EXCEPTION(throwScope, {}); @@ -507,7 +508,7 @@ static inline JSC::EncodedJSValue jsURLSearchParamsPrototypeFunction_setBody(JSC UNUSED_PARAM(callFrame); auto& impl = castedThis->wrapped(); if (callFrame->argumentCount() < 2) [[unlikely]] - return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); + return Bun::ERR::MISSING_ARGS(throwScope, lexicalGlobalObject, "The \"name\" and \"value\" arguments must be specified"_s); EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); auto name = convert(*lexicalGlobalObject, argument0.value()); RETURN_IF_EXCEPTION(throwScope, {}); diff --git a/src/runtime/api/bun/h2_frame_parser.rs b/src/runtime/api/bun/h2_frame_parser.rs index 3946d78284ee..894eec453184 100644 --- a/src/runtime/api/bun/h2_frame_parser.rs +++ b/src/runtime/api/bun/h2_frame_parser.rs @@ -7111,9 +7111,9 @@ impl H2FrameParser { } stream.attach_signal(this, signal_); } else { - return Err(global_object.throw_invalid_argument_type_value( + return Err(global_object.throw_invalid_argument_type_list( b"options.signal", - b"AbortSignal", + &[b"AbortSignal"], signal_arg, )); } diff --git a/src/runtime/api/bun/js_bun_spawn_bindings.rs b/src/runtime/api/bun/js_bun_spawn_bindings.rs index 4b27d7e13a21..a7a3e228b4a5 100644 --- a/src/runtime/api/bun/js_bun_spawn_bindings.rs +++ b/src/runtime/api/bun/js_bun_spawn_bindings.rs @@ -549,9 +549,9 @@ fn spawn_maybe_sync( } **abort_signal = Some(sig.ref_()); } else { - return Err(global_this.throw_invalid_argument_type_value( + return Err(global_this.throw_invalid_argument_type_list( b"signal", - b"AbortSignal", + &[b"AbortSignal"], signal_val, )); } diff --git a/src/runtime/crypto/PBKDF2.rs b/src/runtime/crypto/PBKDF2.rs index ab6044ebf277..6964f8b5b8c4 100644 --- a/src/runtime/crypto/PBKDF2.rs +++ b/src/runtime/crypto/PBKDF2.rs @@ -194,9 +194,15 @@ impl PBKDF2 { )? { Some(v) => v, None => { - return Err(global_this.throw_invalid_argument_type_value( + return Err(global_this.throw_invalid_argument_type_list( b"salt", - b"string or buffer", + &[ + b"string", + b"ArrayBuffer", + b"Buffer", + b"TypedArray", + b"DataView", + ], arg1, )); } @@ -214,9 +220,15 @@ impl PBKDF2 { )? { Some(v) => v, None => { - return Err(global_this.throw_invalid_argument_type_value( + return Err(global_this.throw_invalid_argument_type_list( b"password", - b"string or buffer", + &[ + b"string", + b"ArrayBuffer", + b"Buffer", + b"TypedArray", + b"DataView", + ], arg0, )); } diff --git a/src/runtime/ipc_host.rs b/src/runtime/ipc_host.rs index 08f69af9eb7b..91e745425950 100644 --- a/src/runtime/ipc_host.rs +++ b/src/runtime/ipc_host.rs @@ -143,9 +143,9 @@ pub(crate) fn do_send( && !message.is_boolean() && !message.is_null() { - return Err(global_object.throw_invalid_argument_type_value_one_of( + return Err(global_object.throw_invalid_argument_type_list( b"message", - b"string, object, number, or boolean", + &[b"string", b"object", b"number", b"boolean"], message, )); } diff --git a/src/runtime/node/node_crypto_binding.rs b/src/runtime/node/node_crypto_binding.rs index 3244695f60e0..00068527e3fe 100644 --- a/src/runtime/node/node_crypto_binding.rs +++ b/src/runtime/node/node_crypto_binding.rs @@ -634,9 +634,9 @@ pub mod random { let [buf_value, offset_value, size_value] = call_frame.arguments_as_array::<3>(); let Some(mut buf) = buf_value.as_array_buffer(global) else { - return Err(global.throw_invalid_argument_type_value( + return Err(global.throw_invalid_argument_type_list( b"buf", - b"ArrayBuffer or ArrayBufferView", + &[b"ArrayBuffer", b"ArrayBufferView"], buf_value, )); }; @@ -679,9 +679,9 @@ pub mod random { call_frame.arguments_as_array::<4>(); let Some(buf) = buf_value.as_array_buffer(global) else { - return Err(global.throw_invalid_argument_type_value( + return Err(global.throw_invalid_argument_type_list( b"buf", - b"ArrayBuffer or ArrayBufferView", + &[b"ArrayBuffer", b"ArrayBufferView"], buf_value, )); }; @@ -808,9 +808,15 @@ mod _impl { StringObjects::Allow, )? else { - return Err(global.throw_invalid_argument_type_value( + return Err(global.throw_invalid_argument_type_list( b"password", - b"string, ArrayBuffer, Buffer, TypedArray, or DataView", + &[ + b"string", + b"ArrayBuffer", + b"Buffer", + b"TypedArray", + b"DataView", + ], password_value, )); }; @@ -831,9 +837,15 @@ mod _impl { StringObjects::Allow, )? else { - return Err(global.throw_invalid_argument_type_value( + return Err(global.throw_invalid_argument_type_list( b"salt", - b"string, ArrayBuffer, Buffer, TypedArray, or DataView", + &[ + b"string", + b"ArrayBuffer", + b"Buffer", + b"TypedArray", + b"DataView", + ], salt_value, )); }; diff --git a/src/runtime/node/node_fs.rs b/src/runtime/node/node_fs.rs index 660b8b390a69..e3eb4ec3a245 100644 --- a/src/runtime/node/node_fs.rs +++ b/src/runtime/node/node_fs.rs @@ -2643,17 +2643,17 @@ pub mod args { impl Rename { pub fn from_js(ctx: &JSGlobalObject, arguments: &mut ArgumentsSlice) -> JsResult { let old_path = PathLike::from_js(ctx, arguments)?.ok_or_else(|| { - ctx.throw_invalid_argument_type_value( + ctx.throw_invalid_argument_type_list( b"oldPath", - b"string or an instance of Buffer or URL", + &[b"string", b"Buffer", b"URL"], arguments.next().unwrap_or(JSValue::UNDEFINED), ) })?; // `Drop for PathLike` runs on early return. let new_path = PathLike::from_js(ctx, arguments)?.ok_or_else(|| { - ctx.throw_invalid_argument_type_value( + ctx.throw_invalid_argument_type_list( b"newPath", - b"string or an instance of Buffer or URL", + &[b"string", b"Buffer", b"URL"], arguments.next().unwrap_or(JSValue::UNDEFINED), ) })?; @@ -3437,9 +3437,9 @@ pub mod args { arguments: &mut ArgumentsSlice, ) -> JsResult { let prefix = PathLike::from_js(ctx, arguments)?.ok_or_else(|| { - ctx.throw_invalid_argument_type_value( + ctx.throw_invalid_argument_type_list( b"prefix", - b"string, Buffer, or URL", + &[b"string", b"Buffer", b"URL"], arguments.next().unwrap_or(JSValue::UNDEFINED), ) })?; @@ -3653,12 +3653,16 @@ pub mod args { let bv = buffer_value .ok_or_else(|| ctx.throw_invalid_arguments(format_args!("data is required")))?; let buffer = StringOrBuffer::from_js(ctx, bv)?.ok_or_else(|| { - ctx.throw_invalid_argument_type_value(b"buffer", b"string or TypedArray", bv) + ctx.throw_invalid_argument_type_list( + b"buffer", + &[b"string", b"Buffer", b"TypedArray", b"DataView"], + bv, + ) })?; if bv.is_string() && !bv.is_string_literal() { - return Err(ctx.throw_invalid_argument_type_value( + return Err(ctx.throw_invalid_argument_type_list( b"buffer", - b"string or TypedArray", + &[b"string", b"Buffer", b"TypedArray", b"DataView"], bv, )); } @@ -3849,7 +3853,11 @@ pub mod args { 0.0 }; let buffer = Buffer::from_js(ctx, buffer_value).ok_or_else(|| { - ctx.throw_invalid_argument_type_value(b"buffer", b"TypedArray", buffer_value) + ctx.throw_invalid_argument_type_list( + b"buffer", + &[b"Buffer", b"TypedArray", b"DataView"], + buffer_value, + ) })?; // if (length === 0) { @@ -4078,9 +4086,9 @@ pub mod args { signal.pending_activity_ref(); *abort_signal = Some(signal); } else { - return Err(ctx.throw_invalid_argument_type_value( + return Err(ctx.throw_invalid_argument_type_list( b"signal", - b"AbortSignal", + &[b"AbortSignal"], value, )); } @@ -4187,9 +4195,9 @@ pub mod args { signal.pending_activity_ref(); *abort_signal = Some(signal); } else { - return Err(ctx.throw_invalid_argument_type_value( + return Err(ctx.throw_invalid_argument_type_list( b"signal", - b"AbortSignal", + &[b"AbortSignal"], value, )); } diff --git a/src/runtime/node/node_zlib_binding.rs b/src/runtime/node/node_zlib_binding.rs index 64c281d407fb..ec6aab46afe8 100644 --- a/src/runtime/node/node_zlib_binding.rs +++ b/src/runtime/node/node_zlib_binding.rs @@ -105,9 +105,9 @@ pub(crate) fn crc32(global_this: &JSGlobalObject, callframe: &CallFrame) -> JsRe let data: JSValue = arguments[0]; if callframe.arguments_count() < 1 { - return Err(global_this.throw_invalid_argument_type_value( + return Err(global_this.throw_invalid_argument_type_list( b"data", - b"string or an instance of Buffer, TypedArray, or DataView", + &[b"string", b"Buffer", b"TypedArray", b"DataView"], JSValue::UNDEFINED, )); } diff --git a/src/runtime/node/zlib/NativeBrotli.rs b/src/runtime/node/zlib/NativeBrotli.rs index 62ab57906e08..4303997b3f9e 100644 --- a/src/runtime/node/zlib/NativeBrotli.rs +++ b/src/runtime/node/zlib/NativeBrotli.rs @@ -209,16 +209,16 @@ mod _impl { // caller-supplied array must hold at least 2 elements. let write_result_value = arguments.ptr[1]; let Some(mut write_result_buf) = write_result_value.as_array_buffer(global_this) else { - return Err(global_this.throw_invalid_argument_type_value( + return Err(global_this.throw_invalid_argument_type_list( "writeResult", - "Uint32Array", + &[b"Uint32Array"], write_result_value, )); }; if write_result_buf.typed_array_type != bun_jsc::JSType::Uint32Array { - return Err(global_this.throw_invalid_argument_type_value( + return Err(global_this.throw_invalid_argument_type_list( "writeResult", - "Uint32Array", + &[b"Uint32Array"], write_result_value, )); } @@ -239,16 +239,16 @@ mod _impl { // bytes, so the element type must actually be Uint32Array. let params_value = arguments.ptr[0]; let Some(mut params_buf) = params_value.as_array_buffer(global_this) else { - return Err(global_this.throw_invalid_argument_type_value( + return Err(global_this.throw_invalid_argument_type_list( "params", - "Uint32Array", + &[b"Uint32Array"], params_value, )); }; if params_buf.typed_array_type != bun_jsc::JSType::Uint32Array { - return Err(global_this.throw_invalid_argument_type_value( + return Err(global_this.throw_invalid_argument_type_list( "params", - "Uint32Array", + &[b"Uint32Array"], params_value, )); } @@ -263,9 +263,9 @@ mod _impl { dictionary_buf = match dictionary_value.as_array_buffer(global_this) { Some(buf) => buf, None => { - return Err(global_this.throw_invalid_argument_type_value( + return Err(global_this.throw_invalid_argument_type_list( "dictionary", - "Buffer, TypedArray, or DataView", + &[b"Buffer", b"TypedArray", b"DataView"], dictionary_value, )); } diff --git a/src/runtime/node/zlib/NativeZlib.rs b/src/runtime/node/zlib/NativeZlib.rs index 399c3772a69e..3f28c1df2810 100644 --- a/src/runtime/node/zlib/NativeZlib.rs +++ b/src/runtime/node/zlib/NativeZlib.rs @@ -151,16 +151,16 @@ mod _impl { // caller-supplied array must hold at least 2 elements. let write_result_value = arguments.ptr[4]; let Some(mut write_result_buf) = write_result_value.as_array_buffer(global) else { - return Err(global.throw_invalid_argument_type_value( + return Err(global.throw_invalid_argument_type_list( "writeResult", - "Uint32Array", + &[b"Uint32Array"], write_result_value, )); }; if write_result_buf.typed_array_type != bun_jsc::JSType::Uint32Array { - return Err(global.throw_invalid_argument_type_value( + return Err(global.throw_invalid_argument_type_list( "writeResult", - "Uint32Array", + &[b"Uint32Array"], write_result_value, )); } @@ -185,9 +185,9 @@ mod _impl { dictionary_buf = match dictionary_value.as_array_buffer(global) { Some(buf) => buf, None => { - return Err(global.throw_invalid_argument_type_value( + return Err(global.throw_invalid_argument_type_list( "dictionary", - "Buffer, TypedArray, or DataView", + &[b"Buffer", b"TypedArray", b"DataView"], dictionary_value, )); } diff --git a/src/runtime/node/zlib/NativeZstd.rs b/src/runtime/node/zlib/NativeZstd.rs index 70b0465c04dc..6cff8cdbf9c6 100644 --- a/src/runtime/node/zlib/NativeZstd.rs +++ b/src/runtime/node/zlib/NativeZstd.rs @@ -169,16 +169,16 @@ mod _impl { let process_callback_value = arguments[3]; let Some(mut write_state) = write_state_value.as_array_buffer(global) else { - return Err(global.throw_invalid_argument_type_value( + return Err(global.throw_invalid_argument_type_list( "writeState", - "Uint32Array", + &[b"Uint32Array"], write_state_value, )); }; if write_state.typed_array_type != jsc::JSType::Uint32Array { - return Err(global.throw_invalid_argument_type_value( + return Err(global.throw_invalid_argument_type_list( "writeState", - "Uint32Array", + &[b"Uint32Array"], write_state_value, )); } @@ -224,9 +224,9 @@ mod _impl { dictionary_buf = match dictionary_value.as_array_buffer(global) { Some(buf) => buf, None => { - return Err(global.throw_invalid_argument_type_value( + return Err(global.throw_invalid_argument_type_list( "dictionary", - "Buffer, TypedArray, or DataView", + &[b"Buffer", b"TypedArray", b"DataView"], dictionary_value, )); } @@ -243,16 +243,16 @@ mod _impl { } let Some(mut params_) = init_params_array_value.as_array_buffer(global) else { - return Err(global.throw_invalid_argument_type_value( + return Err(global.throw_invalid_argument_type_list( "initParamsArray", - "Uint32Array", + &[b"Uint32Array"], init_params_array_value, )); }; if params_.typed_array_type != jsc::JSType::Uint32Array { - return Err(global.throw_invalid_argument_type_value( + return Err(global.throw_invalid_argument_type_list( "initParamsArray", - "Uint32Array", + &[b"Uint32Array"], init_params_array_value, )); } diff --git a/src/runtime/socket/socket_body.rs b/src/runtime/socket/socket_body.rs index 40d5befa04f1..3732d73c4d94 100644 --- a/src/runtime/socket/socket_body.rs +++ b/src/runtime/socket/socket_body.rs @@ -3484,9 +3484,9 @@ impl NewSocket { }; if !sc_js.is_empty() { let Some(sc) = sc_js.as_class_ref::() else { - return Err(global.throw_invalid_argument_type_value( + return Err(global.throw_invalid_argument_type_list( b"secureContext", - b"SecureContext", + &[b"SecureContext"], sc_js, )); }; @@ -4747,9 +4747,9 @@ pub fn js_upgrade_duplex_to_tls( }; if !sc_js.is_empty() { let Some(sc) = sc_js.as_class_ref::() else { - return Err(global.throw_invalid_argument_type_value( + return Err(global.throw_invalid_argument_type_list( b"secureContext", - b"SecureContext", + &[b"SecureContext"], sc_js, )); }; diff --git a/test/js/node/test/common/README.md b/test/js/node/test/common/README.md new file mode 100644 index 000000000000..6c8fcf42847a --- /dev/null +++ b/test/js/node/test/common/README.md @@ -0,0 +1,1167 @@ +# Node.js Core Test Common Modules + +This directory contains modules used to test the Node.js implementation. +All tests must begin by requiring the `common` module: + +```js +require('../common'); +``` + +This is not just a convenience for exporting helper functions etc; it also performs +several other tasks: + +* Verifies that no unintended globals have been leaked to ensure that tests + don't accidentally pollute the global namespace. + +* Some tests assume a default umask of `0o022`. To enforce this assumption, + the common module sets the umask at startup. Tests that require a + different umask can override this setting after loading the module. + +* Some tests specify runtime flags (example, `--expose-internals`) via a + comment at the top of the file: `// Flags: --expose-internals`. + If the test is run without those flags, the common module automatically + spawns a child process with proper flags. This ensures that the tests + always run under the expected conditions. Because of this behaviour, the + common module must be loaded first so that any code below it is not + executed until the process has been re-spawned with the correct flags. + +## Table of contents + +* [ArrayStream module](#arraystream-module) +* [Benchmark module](#benchmark-module) +* [Child process module](#child-process-module) +* [Common module API](#common-module-api) +* [Countdown module](#countdown-module) +* [CPU Profiler module](#cpu-profiler-module) +* [Debugger module](#debugger-module) +* [DNS module](#dns-module) +* [Environment variables](#environment-variables) +* [Fixtures module](#fixtures-module) +* [Heap dump checker module](#heap-dump-checker-module) +* [hijackstdio module](#hijackstdio-module) +* [HTTP2 module](#http2-module) +* [Internet module](#internet-module) +* [ongc module](#ongc-module) +* [process-exit-code-test-cases module](#process-exit-code-test-cases-module) +* [Report module](#report-module) +* [tick module](#tick-module) +* [tmpdir module](#tmpdir-module) +* [UDP pair helper](#udp-pair-helper) +* [WPT module](#wpt-module) + +## Benchmark module + +The `benchmark` module is used by tests to run benchmarks. + +### `runBenchmark(name, env)` + +* `name` [\][] Name of benchmark suite to be run. +* `env` [\][] Environment variables to be applied during the + run. + +## Child Process module + +The `child_process` module is used by tests that launch child processes. + +### `spawnSyncAndExit(command[, args][, spawnOptions], expectations)` + +Spawns a child process synchronously using [`child_process.spawnSync()`][] and +check if it runs in the way expected. If it does not, print the stdout and +stderr output from the child process and additional information about it to +the stderr of the current process before throwing and error. This helps +gathering more information about test failures coming from child processes. + +* `command`, `args`, `spawnOptions` See [`child_process.spawnSync()`][] +* `expectations` [\][] + * `status` [\][] Expected `child.status` + * `signal` [\][] | `null` Expected `child.signal` + * `stderr` [\][] | [\][] | + [\][] Optional. If it's a string, check that the output + to the stderr of the child process is exactly the same as the string. If + it's a regular expression, check that the stderr matches it. If it's a + function, invoke it with the stderr output as a string and check + that it returns true. The function can just throw errors (e.g. assertion + errors) to provide more information if the check fails. + * `stdout` [\][] | [\][] | + [\][] Optional. Similar to `stderr` but for the stdout. + * `trim` [\][] Optional. Whether this method should trim + out the whitespace characters when checking `stderr` and `stdout` outputs. + Defaults to `false`. +* return [\][] + * `child` [\][] The child process returned by + [`child_process.spawnSync()`][]. + * `stderr` [\][] The output from the child process to stderr. + * `stdout` [\][] The output from the child process to stdout. + +### `spawnSyncAndExitWithoutError(command[, args][, spawnOptions])` + +Similar to `expectSyncExit()` with the `status` expected to be 0 and +`signal` expected to be `null`. + +### `spawnSyncAndAssert(command[, args][, spawnOptions], expectations)` + +Similar to `spawnSyncAndExitWithoutError()`, but with an additional +`expectations` parameter. + +## Common module API + +The `common` module is used by tests for consistency across repeated +tasks. + +### `allowGlobals(...allowlist)` + +* `allowlist` [\][] Array of Globals +* return [\][] + +Takes `allowlist` and concats that with predefined `knownGlobals`. + +### `canCreateSymLink()` + +* return [\][] + +Checks whether the current running process can create symlinks. On Windows, this +returns `false` if the process running doesn't have privileges to create +symlinks +([SeCreateSymbolicLinkPrivilege](https://msdn.microsoft.com/en-us/library/windows/desktop/bb530716\(v=vs.85\).aspx)). +On non-Windows platforms, this always returns `true`. + +### `enoughTestMem` + +* [\][] + +Indicates if there is more than 1gb of total memory. + +### ``escapePOSIXShell`shell command` `` + +Escapes values in a string template literal to pass them as env variable. On Windows, this function +does not escape anything (which is fine for most paths, as `"` is not a valid +char in a path on Windows), so for tests that must pass on Windows, you should +use it only to escape paths, inside double quotes. +This function is meant to be used for tagged template strings. + +```js +const { escapePOSIXShell } = require('../common'); +const fixtures = require('../common/fixtures'); +const { execSync } = require('node:child_process'); +const origin = fixtures.path('origin'); +const destination = fixtures.path('destination'); + +execSync(...escapePOSIXShell`cp "${origin}" "${destination}"`); + +// When you need to specify specific options, and/or additional env variables: +const [cmd, opts] = escapePOSIXShell`cp "${origin}" "${destination}"`; +console.log(typeof cmd === 'string'); // true +console.log(opts === undefined || typeof opts.env === 'object'); // true +execSync(cmd, { ...opts, stdio: 'ignore' }); +execSync(cmd, { stdio: 'ignore', env: { ...opts?.env, KEY: 'value' } }); +``` + +When possible, avoid using a shell; that way, there's no need to escape values. + +### `expectsError(validator[, exact])` + +* `validator` [\][] | [\][] | + [\][] | [\][] The validator behaves + identical to `assert.throws(fn, validator)`. +* `exact` [\][] default = 1 +* return [\][] A callback function that expects an error. + +A function suitable as callback to validate callback based errors. The error is +validated using `assert.throws(() => { throw error; }, validator)`. If the +returned function has not been called exactly `exact` number of times when the +test is complete, then the test will fail. + +### `expectWarning(name[, expected[, code]])` + +* `name` [\][] | [\][] +* `expected` [\][] | [\][] | [\][] +* `code` [\][] + +Tests whether `name`, `expected`, and `code` are part of a raised warning. + +The code is required in case the name is set to `'DeprecationWarning'`. + +Examples: + +```js +const { expectWarning } = require('../common'); + +expectWarning('Warning', 'Foobar is really bad'); + +expectWarning('DeprecationWarning', 'Foobar is deprecated', 'DEP0XXX'); + +expectWarning('DeprecationWarning', [ + 'Foobar is deprecated', 'DEP0XXX', +]); + +expectWarning('DeprecationWarning', [ + ['Foobar is deprecated', 'DEP0XXX'], + ['Baz is also deprecated', 'DEP0XX2'], +]); + +expectWarning('DeprecationWarning', { + DEP0XXX: 'Foobar is deprecated', + DEP0XX2: 'Baz is also deprecated', +}); + +expectWarning({ + DeprecationWarning: { + DEP0XXX: 'Foobar is deprecated', + DEP0XX1: 'Baz is also deprecated', + }, + Warning: [ + ['Multiple array entries are fine', 'SpecialWarningCode'], + ['No code is also fine'], + ], + SingleEntry: ['This will also work', 'WarningCode'], + SingleString: 'Single string entries without code will also work', +}); +``` + +### `getArrayBufferViews(buf)` + +* `buf` [\][] +* return [\][]\[] + +Returns an instance of all possible `ArrayBufferView`s of the provided Buffer. + +### `getBufferSources(buf)` + +* `buf` [\][] +* return [\][]\[] + +Returns an instance of all possible `BufferSource`s of the provided Buffer, +consisting of all `ArrayBufferView` and an `ArrayBuffer`. + +### `getTTYfd()` + +Attempts to get a valid TTY file descriptor. Returns `-1` if it fails. + +The TTY file descriptor is assumed to be capable of being writable. + +### `hasCrypto` + +* [\][] + +Indicates whether OpenSSL is available. + +### `hasIntl` + +* [\][] + +Indicates if [internationalization][] is supported. + +### `hasIPv6` + +* [\][] + +Indicates whether `IPv6` is supported on this platform. + +### `hasSQLite` + +* [\][] + +Indicates whether SQLite is available. + +### `inFreeBSDJail` + +* [\][] + +Checks whether free BSD Jail is true or false. + +### `isAIX` + +* [\][] + +Platform check for Advanced Interactive eXecutive (AIX). + +### `isAlive(pid)` + +* `pid` [\][] +* return [\][] + +Attempts to 'kill' `pid` + +### `isFreeBSD` + +* [\][] + +Platform check for Free BSD. + +### `isIBMi` + +* [\][] + +Platform check for IBMi. + +### `isLinux` + +* [\][] + +Platform check for Linux. + +### `isMacOS` + +* [\][] + +Platform check for macOS. + +### `isSunOS` + +* [\][] + +Platform check for SunOS. + +### `isWindows` + +* [\][] + +Platform check for Windows. + +### `localhostIPv4` + +* [\][] + +IP of `localhost`. + +### `localIPv6Hosts` + +* [\][] + +Array of IPV6 representations for `localhost`. + +### `mustCall([fn][, exact])` + +* `fn` [\][] default = () => {} +* `exact` [\][] default = 1 +* return [\][] + +Returns a function that calls `fn`. If the returned function has not been called +exactly `exact` number of times when the test is complete, then the test will +fail. + +If `fn` is not provided, an empty function will be used. + +### `mustCallAtLeast([fn][, minimum])` + +* `fn` [\][] default = () => {} +* `minimum` [\][] default = 1 +* return [\][] + +Returns a function that calls `fn`. If the returned function has not been called +at least `minimum` number of times when the test is complete, then the test will +fail. + +If `fn` is not provided, an empty function will be used. + +### `mustNotCall([msg])` + +* `msg` [\][] default = 'function should not have been called' +* return [\][] + +Returns a function that triggers an `AssertionError` if it is invoked. `msg` is +used as the error message for the `AssertionError`. + +### `mustNotMutateObjectDeep([target])` + +* `target` [\][] default = `undefined` +* return [\][] + +If `target` is an Object, returns a proxy object that triggers +an `AssertionError` on mutation attempt, including mutation of deeply nested +Objects. Otherwise, it returns `target` directly. + +Use of this function is encouraged for relevant regression tests. + +```mjs +import { open } from 'node:fs/promises'; +import { mustNotMutateObjectDeep } from '../common/index.mjs'; + +const _mutableOptions = { length: 4, position: 8 }; +const options = mustNotMutateObjectDeep(_mutableOptions); + +// In filehandle.read or filehandle.write, attempt to mutate options will throw +// In the test code, options can still be mutated via _mutableOptions +const fh = await open('/path/to/file', 'r+'); +const { buffer } = await fh.read(options); +_mutableOptions.position = 4; +await fh.write(buffer, options); + +// Inline usage +const stats = await fh.stat(mustNotMutateObjectDeep({ bigint: true })); +console.log(stats.size); +``` + +Caveats: built-in objects that make use of their internal slots (for example, +`Map`s and `Set`s) might not work with this function. It returns Functions +directly, not preventing their mutation. + +### `mustSucceed([fn])` + +* `fn` [\][] default = () => {} +* return [\][] + +Returns a function that accepts arguments `(err, ...args)`. If `err` is not +`undefined` or `null`, it triggers an `AssertionError`. Otherwise, it calls +`fn(...args)`. + +### `nodeProcessAborted(exitCode, signal)` + +* `exitCode` [\][] +* `signal` [\][] +* return [\][] + +Returns `true` if the exit code `exitCode` and/or signal name `signal` represent +the exit code and/or signal name of a node process that aborted, `false` +otherwise. + +### `platformTimeout(ms)` + +* `ms` [\][] | [\][] +* return [\][] | [\][] + +Returns a timeout value based on detected conditions. For example, a debug build +may need extra time so the returned value will be larger than on a release +build. + +### `PIPE` + +* [\][] + +Path to the test socket. + +### `PORT` + +* [\][] + +A port number for tests to use if one is needed. + +### `printSkipMessage(msg)` + +* `msg` [\][] + +Logs '1..0 # Skipped: ' + `msg` + +### `pwdCommand` + +* [\][] First two argument for the `spawn`/`exec` functions. + +Platform normalized `pwd` command options. Usage example: + +```js +const common = require('../common'); +const { spawn } = require('node:child_process'); + +spawn(...common.pwdCommand, { stdio: ['pipe'] }); +``` + +### `requireNoPackageJSONAbove([dir])` + +* `dir` [\][] default = \_\_dirname + +Throws an `AssertionError` if a `package.json` file exists in any ancestor +directory above `dir`. Such files may interfere with proper test functionality. + +### `runWithInvalidFD(func)` + +* `func` [\][] + +Runs `func` with an invalid file descriptor that is an unsigned integer and +can be used to trigger `EBADF` as the first argument. If no such file +descriptor could be generated, a skip message will be printed and the `func` +will not be run. + +### `skip(msg)` + +* `msg` [\][] + +Logs '1..0 # Skipped: ' + `msg` and exits with exit code `0`. + +### `skipIfEslintMissing()` + +Skip the rest of the tests in the current file when `ESLint` is not available +at `tools/eslint/node_modules/eslint` + +### `skipIfInspectorDisabled()` + +Skip the rest of the tests in the current file when the Inspector +was disabled at compile time. + +### `skipIfSQLiteMissing()` + +Skip the rest of the tests in the current file when the SQLite +was disabled at compile time. + +### `skipIf32Bits()` + +Skip the rest of the tests in the current file when the Node.js executable +was compiled with a pointer size smaller than 64 bits. + +## ArrayStream module + +The `ArrayStream` module provides a simple `Stream` that pushes elements from +a given array. + + + +```js +const ArrayStream = require('../common/arraystream'); +const stream = new ArrayStream(); +stream.run(['a', 'b', 'c']); +``` + +It can be used within tests as a simple mock stream. + +## Countdown module + +The `Countdown` module provides a simple countdown mechanism for tests that +require a particular action to be taken after a given number of completed +tasks (for instance, shutting down an HTTP server after a specific number of +requests). The Countdown will fail the test if the remainder did not reach 0. + + + +```js +const Countdown = require('../common/countdown'); + +function doSomething() { + console.log('.'); +} + +const countdown = new Countdown(2, doSomething); +countdown.dec(); +countdown.dec(); +``` + +### `new Countdown(limit, callback)` + +* `limit` {number} +* `callback` {function} + +Creates a new `Countdown` instance. + +### `Countdown.prototype.dec()` + +Decrements the `Countdown` counter. + +### `Countdown.prototype.remaining` + +Specifies the remaining number of times `Countdown.prototype.dec()` must be +called before the callback is invoked. + +## CPU Profiler module + +The `cpu-prof` module provides utilities related to CPU profiling tests. + +### `env` + +* Default: { ...process.env, NODE\_DEBUG\_NATIVE: 'INSPECTOR\_PROFILER' } + +Environment variables used in profiled processes. + +### `getCpuProfiles(dir)` + +* `dir` {string} The directory containing the CPU profile files. +* return [\][] + +Returns an array of all `.cpuprofile` files found in `dir`. + +### `getFrames(file, suffix)` + +* `file` {string} Path to a `.cpuprofile` file. +* `suffix` {string} Suffix of the URL of call frames to retrieve. +* returns { frames: [\][], nodes: [\][] } + +Returns an object containing an array of the relevant call frames and an array +of all the profile nodes. + +### `kCpuProfInterval` + +Sampling interval in microseconds. + +### `verifyFrames(output, file, suffix)` + +* `output` {string} +* `file` {string} +* `suffix` {string} + +Throws an `AssertionError` if there are no call frames with the expected +`suffix` in the profiling data contained in `file`. + +## Debugger module + +Provides common functionality for tests for `node inspect`. + +### `startCLI(args[[, flags], spawnOpts])` + +* `args` [\][] +* `flags` [\][] default = \[] +* `showOpts` [\][] default = {} +* return [\][] + +Returns a null-prototype object with properties that are functions and getters +used to interact with the `node inspect` CLI. These functions are: + +* `flushOutput()` +* `waitFor()` +* `waitForPrompt()` +* `waitForInitialBreak()` +* `breakInfo` +* `ctrlC()` +* `output` +* `rawOutput` +* `parseSourceLines()` +* `writeLine()` +* `command()` +* `stepCommand()` +* `quit()` + +## `DNS` module + +The `DNS` module provides utilities related to the `dns` built-in module. + +### `errorLookupMock(code, syscall)` + +* `code` [\][] Defaults to `dns.mockedErrorCode`. +* `syscall` [\][] Defaults to `dns.mockedSysCall`. +* return [\][] + +A mock for the `lookup` option of `net.connect()` that would result in an error +with the `code` and the `syscall` specified. Returns a function that has the +same signature as `dns.lookup()`. + +### `mockedErrorCode` + +The default `code` of errors generated by `errorLookupMock`. + +### `mockedSysCall` + +The default `syscall` of errors generated by `errorLookupMock`. + +### `readDomainFromPacket(buffer, offset)` + +* `buffer` [\][] +* `offset` [\][] +* return [\][] + +Reads the domain string from a packet and returns an object containing the +number of bytes read and the domain. + +### `parseDNSPacket(buffer)` + +* `buffer` [\][] +* return [\][] + +Parses a DNS packet. Returns an object with the values of the various flags of +the packet depending on the type of packet. + +### `writeIPv6(ip)` + +* `ip` [\][] +* return [\][] + +Reads an IPv6 String and returns a Buffer containing the parts. + +### `writeDomainName(domain)` + +* `domain` [\][] +* return [\][] + +Reads a Domain String and returns a Buffer containing the domain. + +### `writeDNSPacket(parsed)` + +* `parsed` [\][] +* return [\][] + +Takes in a parsed Object and writes its fields to a DNS packet as a Buffer +object. + +## Environment variables + +The behavior of the Node.js test suite can be altered using the following +environment variables. + +### `NODE_COMMON_PORT` + +If set, `NODE_COMMON_PORT`'s value overrides the `common.PORT` default value of +12346\. + +### `NODE_REGENERATE_SNAPSHOTS` + +If set, test snapshots for a the current test are regenerated. +for example `NODE_REGENERATE_SNAPSHOTS=1 out/Release/node test/parallel/test-runner-output.mjs` +will update all the test runner output snapshots. + +### `NODE_SKIP_FLAG_CHECK` + +If set, command line arguments passed to individual tests are not validated. + +### `NODE_SKIP_CRYPTO` + +If set, crypto tests are skipped. + +### `NODE_TEST_KNOWN_GLOBALS` + +A comma-separated list of variables names that are appended to the global +variable allowlist. Alternatively, if `NODE_TEST_KNOWN_GLOBALS` is set to `'0'`, +global leak detection is disabled. + +## Fixtures module + +The `common/fixtures` module provides convenience methods for working with +files in the `test/fixtures` directory. + +### `fixtures.fixturesDir` + +* [\][] + +The absolute path to the `test/fixtures/` directory. + +### `fixtures.path(...args)` + +* `...args` [\][] + +Returns the result of `path.join(fixtures.fixturesDir, ...args)`. + +### `fixtures.fileURL(...args)` + +* `...args` [\][] + +Returns the result of `url.pathToFileURL(fixtures.path(...args))`. + +### `fixtures.readSync(args[, enc])` + +* `args` [\][] | [\][] + +Returns the result of +`fs.readFileSync(path.join(fixtures.fixturesDir, ...args), 'enc')`. + +### `fixtures.readKey(arg[, enc])` + +* `arg` [\][] + +Returns the result of +`fs.readFileSync(path.join(fixtures.fixturesDir, 'keys', arg), 'enc')`. + +## Heap dump checker module + +This provides utilities for checking the validity of heap dumps. +This requires the usage of `--expose-internals`. + +### `heap.recordState()` + +Create a heap dump and an embedder graph copy for inspection. +The returned object has a `validateSnapshotNodes` function similar to the +one listed below. (`heap.validateSnapshotNodes(...)` is a shortcut for +`heap.recordState().validateSnapshotNodes(...)`.) + +### `heap.validateSnapshotNodes(name, expected, options)` + +* `name` [\][] Look for this string as the name of heap dump + nodes. +* `expected` [\][] A list of objects, possibly with an `children` + property that points to expected other adjacent nodes. +* `options` [\][] + * `loose` [\][] Do not expect an exact listing of + occurrences of nodes with name `name` in `expected`. + +Create a heap dump and an embedder graph copy and validate occurrences. + + + +```js +validateSnapshotNodes('TLSWRAP', [ + { + children: [ + { name: 'enc_out' }, + { name: 'enc_in' }, + { name: 'TLSWrap' }, + ], + }, +]); +``` + +## hijackstdio module + +The `hijackstdio` module provides utility functions for temporarily redirecting +`stdout` and `stderr` output. + + + +```js +const { hijackStdout, restoreStdout } = require('../common/hijackstdio'); + +hijackStdout((data) => { + /* Do something with data */ + restoreStdout(); +}); + +console.log('this is sent to the hijacked listener'); +``` + +### `hijackStderr(listener)` + +* `listener` [\][]: a listener with a single parameter + called `data`. + +Eavesdrop to `process.stderr.write()` calls. Once `process.stderr.write()` is +called, `listener` will also be called and the `data` of `write` function will +be passed to `listener`. What's more, `process.stderr.writeTimes` is a count of +the number of calls. + +### `hijackStdout(listener)` + +* `listener` [\][]: a listener with a single parameter + called `data`. + +Eavesdrop to `process.stdout.write()` calls. Once `process.stdout.write()` is +called, `listener` will also be called and the `data` of `write` function will +be passed to `listener`. What's more, `process.stdout.writeTimes` is a count of +the number of calls. + +### restoreStderr() + +Restore the original `process.stderr.write()`. Used to restore `stderr` to its +original state after calling [`hijackstdio.hijackStdErr()`][]. + +### restoreStdout() + +Restore the original `process.stdout.write()`. Used to restore `stdout` to its +original state after calling [`hijackstdio.hijackStdOut()`][]. + +## HTTP/2 module + +The http2.js module provides a handful of utilities for creating mock HTTP/2 +frames for testing of HTTP/2 endpoints + + + +```js +const http2 = require('../common/http2'); +``` + +### Class: `Frame` + +The `http2.Frame` is a base class that creates a `Buffer` containing a +serialized HTTP/2 frame header. + + + +```js +// length is a 24-bit unsigned integer +// type is an 8-bit unsigned integer identifying the frame type +// flags is an 8-bit unsigned integer containing the flag bits +// id is the 32-bit stream identifier, if any. +const frame = new http2.Frame(length, type, flags, id); + +// Write the frame data to a socket +socket.write(frame.data); +``` + +The serialized `Buffer` may be retrieved using the `frame.data` property. + +### Class: `HeadersFrame` + +The `http2.HeadersFrame` is a subclass of `http2.Frame` that serializes a +`HEADERS` frame. + + + +```js +// id is the 32-bit stream identifier +// payload is a Buffer containing the HEADERS payload (see either +// http2.kFakeRequestHeaders or http2.kFakeResponseHeaders). +// padlen is an 8-bit integer giving the number of padding bytes to include +// final is a boolean indicating whether the End-of-stream flag should be set, +// defaults to false. +const frame = new http2.HeadersFrame(id, payload, padlen, final); + +socket.write(frame.data); +``` + +### Class: `SettingsFrame` + +The `http2.SettingsFrame` is a subclass of `http2.Frame` that serializes an +empty `SETTINGS` frame. + + + +```js +// ack is a boolean indicating whether or not to set the ACK flag. +const frame = new http2.SettingsFrame(ack); + +socket.write(frame.data); +``` + +### `http2.kFakeRequestHeaders` + +Set to a `Buffer` instance that contains a minimal set of serialized HTTP/2 +request headers to be used as the payload of a `http2.HeadersFrame`. + + + +```js +const frame = new http2.HeadersFrame(1, http2.kFakeRequestHeaders, 0, true); + +socket.write(frame.data); +``` + +### `http2.kFakeResponseHeaders` + +Set to a `Buffer` instance that contains a minimal set of serialized HTTP/2 +response headers to be used as the payload a `http2.HeadersFrame`. + + + +```js +const frame = new http2.HeadersFrame(1, http2.kFakeResponseHeaders, 0, true); + +socket.write(frame.data); +``` + +### `http2.kClientMagic` + +Set to a `Buffer` containing the preamble bytes an HTTP/2 client must send +upon initial establishment of a connection. + + + +```js +socket.write(http2.kClientMagic); +``` + +## Internet module + +The `common/internet` module provides utilities for working with +internet-related tests. + +### `internet.addresses` + +* [\][] + * `INET_HOST` [\][] A generic host that has registered common + DNS records, supports both IPv4 and IPv6, and provides basic HTTP/HTTPS + services + * `INET4_HOST` [\][] A host that provides IPv4 services + * `INET6_HOST` [\][] A host that provides IPv6 services + * `INET4_IP` [\][] An accessible IPv4 IP, defaults to the + Google Public DNS IPv4 address + * `INET6_IP` [\][] An accessible IPv6 IP, defaults to the + Google Public DNS IPv6 address + * `INVALID_HOST` [\][] An invalid host that cannot be resolved + * `MX_HOST` [\][] A host with MX records registered + * `SRV_HOST` [\][] A host with SRV records registered + * `PTR_HOST` [\][] A host with PTR records registered + * `NAPTR_HOST` [\][] A host with NAPTR records registered + * `SOA_HOST` [\][] A host with SOA records registered + * `CNAME_HOST` [\][] A host with CNAME records registered + * `NS_HOST` [\][] A host with NS records registered + * `TXT_HOST` [\][] A host with TXT records registered + * `DNS4_SERVER` [\][] An accessible IPv4 DNS server + * `DNS6_SERVER` [\][] An accessible IPv6 DNS server + +A set of addresses for internet-related tests. All properties are configurable +via `NODE_TEST_*` environment variables. For example, to configure +`internet.addresses.INET_HOST`, set the environment +variable `NODE_TEST_INET_HOST` to a specified host. + +## ongc module + +The `ongc` module allows a garbage collection listener to be installed. The +module exports a single `onGC()` function. + +```js +require('../common'); +const { onGC } = require('../common/gc'); + +onGC({}, { ongc() { console.log('collected'); } }); +``` + +### `onGC(target, listener)` + +* `target` [\][] +* `listener` [\][] + * `ongc` [\][] + +Installs a GC listener for the collection of `target`. + +This uses `async_hooks` for GC tracking. This means that it enables +`async_hooks` tracking, which may affect the test functionality. It also +means that between a `global.gc()` call and the listener being invoked +a full `setImmediate()` invocation passes. + +`listener` is an object to make it easier to use a closure; the target object +should not be in scope when `listener.ongc()` is created. + +## process-exit-code-test-cases module + +The `process-exit-code-test-cases` module provides a set of shared test cases +for testing the exit codes of the `process` object. The test cases are shared +between `test/parallel/test-process-exit-code.js` and +`test/parallel/test-worker-exit-code.js`. + +### `getTestCases(isWorker)` + +* `isWorker` [\][] +* return [\][] + +Returns an array of test cases for testing the exit codes of the `process`. Each +test case is an object with a `func` property that is a function that runs the +test case, a `result` property that is the expected exit code, and sometimes an +`error` property that is a regular expression that the error message should +match when the test case is run in a worker thread. + +The `isWorker` parameter is used to adjust the test cases for worker threads. +The default value is `false`. + +## Report module + +The `report` module provides helper functions for testing diagnostic reporting +functionality. + +### `findReports(pid, dir)` + +* `pid` [\][] Process ID to retrieve diagnostic report files + for. +* `dir` [\][] Directory to search for diagnostic report files. +* return [\][] + +Returns an array of diagnostic report file names found in `dir`. The files +should have been generated by a process whose PID matches `pid`. + +### `validate(filepath)` + +* `filepath` [\][] Diagnostic report filepath to validate. + +Validates the schema of a diagnostic report file whose path is specified in +`filepath`. If the report fails validation, an exception is thrown. + +### `validateContent(report)` + +* `report` [\][] | [\][] JSON contents of a + diagnostic report file, the parsed Object thereof, or the result of + `process.report.getReport()`. + +Validates the schema of a diagnostic report whose content is specified in +`report`. If the report fails validation, an exception is thrown. + +## SEA Module + +The `sea` module provides helper functions for testing Single Executable +Application functionality. + +### `skipIfSingleExecutableIsNotSupported()` + +Skip the rest of the tests if single executable applications are not supported +in the current configuration. + +### `generateSEA(targetExecutable, sourceExecutable, seaBlob, verifyWorkflow)` + +Copy `sourceExecutable` to `targetExecutable`, use postject to inject `seaBlob` +into `targetExecutable` and sign it if necessary. + +If `verifyWorkflow` is false (default) and any of the steps fails, +it skips the tests. Otherwise, an error is thrown. + +## tick module + +The `tick` module provides a helper function that can be used to call a callback +after a given number of event loop "ticks". + +### `tick(x, cb)` + +* `x` [\][] Number of event loop "ticks". +* `cb` [\][] A callback function. + +## tmpdir module + +The `tmpdir` module supports the use of a temporary directory for testing. + +### `path` + +* [\][] + +The realpath of the testing temporary directory. + +### `fileURL([...paths])` + +* `...paths` [\][] +* return [\][] + +Resolves a sequence of paths into absolute url in the temporary directory. + +When called without arguments, returns absolute url of the testing +temporary directory with explicit trailing `/`. + +### `refresh(useSpawn)` + +* `useSpawn` [\][] default = false + +Deletes and recreates the testing temporary directory. When `useSpawn` is true +this action is performed using `child_process.spawnSync`. + +The first time `refresh()` runs, it adds a listener to process `'exit'` that +cleans the temporary directory. Thus, every file under `tmpdir.path` needs to +be closed before the test completes. A good way to do this is to add a +listener to process `'beforeExit'`. If a file needs to be left open until +Node.js completes, use a child process and call `refresh()` only in the +parent. + +It is usually only necessary to call `refresh()` once in a test file. +Avoid calling it more than once in an asynchronous context as one call +might refresh the temporary directory of a different context, causing +the test to fail somewhat mysteriously. + +### `resolve([...paths])` + +* `...paths` [\][] +* return [\][] + +Resolves a sequence of paths into absolute path in the temporary directory. + +### `hasEnoughSpace(size)` + +* `size` [\][] Required size, in bytes. + +Returns `true` if the available blocks of the file system underlying `path` +are likely sufficient to hold a single file of `size` bytes. This is useful for +skipping tests that require hundreds of megabytes or even gigabytes of temporary +files, but it is inaccurate and susceptible to race conditions. + +## WPT module + +### `harness` + +A legacy port of [Web Platform Tests][] harness. + +See the source code for definitions. Please avoid using it in new +code - the current usage of this port in tests is being migrated to +the original WPT harness, see [the WPT tests README][]. + +### Class: `WPTRunner` + +A driver class for running WPT with the WPT harness in a worker thread. + +See [the WPT tests README][] for details. + +[]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array +[]: https://developer.mozilla.org/en-US/docs/Web/API/ArrayBufferView +[]: https://nodejs.org/api/buffer.html#buffer_class_buffer +[]: https://developer.mozilla.org/en-US/docs/Web/API/BufferSource +[]: ../../doc/api/child_process.md#class-childprocess +[]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error +[]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function +[]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object +[]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp +[]: https://developer.mozilla.org/en-US/docs/Web/API/URL +[]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types +[]: https://github.com/tc39/proposal-bigint +[]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type +[]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type +[]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type +[Web Platform Tests]: https://github.com/web-platform-tests/wpt +[`child_process.spawnSync()`]: ../../doc/api/child_process.md#child_processspawnsynccommand-args-options +[`hijackstdio.hijackStdErr()`]: #hijackstderrlistener +[`hijackstdio.hijackStdOut()`]: #hijackstdoutlistener +[internationalization]: ../../doc/api/intl.md +[the WPT tests README]: ../wpt/README.md diff --git a/test/js/node/test/common/benchmark.js b/test/js/node/test/common/benchmark.js index 7211ff8703e0..fe8ac8d7c0a4 100644 --- a/test/js/node/test/common/benchmark.js +++ b/test/js/node/test/common/benchmark.js @@ -42,7 +42,7 @@ function runBenchmark(name, env) { for (let testIdx = 1; testIdx < splitTests.length - 1; testIdx++) { const lines = splitTests[testIdx].split('\n'); - assert.ok(/.+/.test(lines[0])); + assert.match(lines[0], /.+/); if (!lines[1].includes('group="')) { assert.strictEqual(lines.length, 2, `benchmark file not running exactly one configuration in test: ${stdout}`); diff --git a/test/js/node/test/common/child_process.js b/test/js/node/test/common/child_process.js index 6c2bc6c9614a..d8c957bdf09c 100644 --- a/test/js/node/test/common/child_process.js +++ b/test/js/node/test/common/child_process.js @@ -86,8 +86,22 @@ function expectSyncExit(caller, spawnArgs, { console.error(`${tag} status = ${child.status}, signal = ${child.signal}`); const error = new Error(`${failures.join('\n')}`); - if (spawnArgs[2]) { - error.options = spawnArgs[2]; + if (typeof spawnArgs[2] === 'object' && spawnArgs[2] !== null) { + const envInOptions = spawnArgs[2].env; + // If the env is overridden in the spawn options, include it in the error + // object for easier debugging. + if (typeof envInOptions === 'object' && envInOptions !== null && envInOptions !== process.env) { + // Only include the environment variables that are different from + // the current process.env to avoid cluttering the output. + error.options = { ...spawnArgs[2], env: {} }; + for (const key of Object.keys(envInOptions)) { + if (envInOptions[key] !== process.env[key]) { + error.options.env[key] = spawnArgs[2].env[key]; + } + } + } else { + error.options = spawnArgs[2]; + } } let command = spawnArgs[0]; if (Array.isArray(spawnArgs[1])) { diff --git a/test/js/node/test/common/debugger-probe.js b/test/js/node/test/common/debugger-probe.js new file mode 100644 index 000000000000..c2ed825a2606 --- /dev/null +++ b/test/js/node/test/common/debugger-probe.js @@ -0,0 +1,85 @@ +'use strict'; + +const assert = require('assert'); + +// Work around a pre-existing inspector issue: if the debuggee exits too quickly +// the inspector can segfault while tearing down. For now normalize the segfault +// back to the expected terminal event (e.g. "completed" or "miss") +// until the upstream bug is fixed. +// See https://github.com/nodejs/node/issues/62765 +// https://github.com/nodejs/node/issues/58245 +const probeTargetExitSignal = 'SIGSEGV'; + +function isProbeSegvTeardown(result) { + if (result?.event !== 'error') { return false; } + const error = result.error; + if (error?.signal !== probeTargetExitSignal) { return false; } + return error.code === 'probe_target_exit' || error.code === 'probe_failure'; +} + +function findProbeSegvTeardownLine(output) { + const signalPrefix = `Target exited with signal ${probeTargetExitSignal}`; + if (output.startsWith(signalPrefix)) { return 0; } + const idx = output.indexOf(`\n${signalPrefix}`); + return idx === -1 ? -1 : idx + 1; +} + +// Replace volatile fields in a probe report (stack frames, Node.js version, +// scriptId, callFrames) with stable placeholders for deepStrictEqual. +function normalizeProbeReport(value) { + if (typeof value === 'string') { + return value + .replace(/(?:\n[ \t]+at\s[^\n]*)+/g, '\n') + .replace(/\nNode\.js v[^\n]+/g, '\nNode.js '); + } + if (Array.isArray(value)) { + return value.map(normalizeProbeReport); + } + if (value !== null && typeof value === 'object') { + const result = {}; + for (const key of Object.keys(value)) { + if (key === 'scriptId') { + result[key] = ''; + } else if (key === 'callFrames') { + result[key] = ''; + } else { + result[key] = normalizeProbeReport(value[key]); + } + } + return result; + } + return value; +} + +function assertProbeJson(output, expected) { + const normalized = typeof output === 'string' ? JSON.parse(output) : output; + const lastResult = normalized.results?.[normalized.results.length - 1]; + + if (isProbeSegvTeardown(lastResult)) { + // Log to facilitate debugging if this normalization is occurring. + console.log('Normalizing trailing SIGSEGV in JSON probe output'); + normalized.results[normalized.results.length - 1] = expected.results.at(-1); + } + + assert.deepStrictEqual(normalizeProbeReport(normalized), normalizeProbeReport(expected)); +} + +function assertProbeText(output, expected) { + const lineStart = findProbeSegvTeardownLine(output); + let normalized; + if (lineStart !== -1) { + // Log to facilitate debugging if this normalization is occurring. + console.log('Normalizing trailing SIGSEGV in text probe output'); + const expectedLineStart = expected.lastIndexOf('\n'); + const terminalLine = expectedLineStart === -1 ? expected : expected.slice(expectedLineStart + 1); + normalized = lineStart === 0 ? terminalLine : `${output.slice(0, lineStart - 1)}\n${terminalLine}`; + } else { + normalized = output; + } + assert.strictEqual(normalized, expected); +} + +module.exports = { + assertProbeJson, + assertProbeText, +}; diff --git a/test/js/node/test/common/debugger.js b/test/js/node/test/common/debugger.js index d5d77fc7c648..dbaa62e71d3f 100644 --- a/test/js/node/test/common/debugger.js +++ b/test/js/node/test/common/debugger.js @@ -7,11 +7,10 @@ const BREAK_MESSAGE = new RegExp('(?:' + [ 'exception', 'other', 'promiseRejection', 'step', ].join('|') + ') in', 'i'); -let TIMEOUT = common.platformTimeout(5000); -if (common.isWindows) { - // Some of the windows machines in the CI need more time to receive - // the outputs from the client. - // https://github.com/nodejs/build/issues/3014 +let TIMEOUT = common.platformTimeout(10000); +// Some macOS and Windows machines require more time to receive the outputs from the client. +// https://github.com/nodejs/build/issues/3014 +if (common.isWindows || common.isMacOS) { TIMEOUT = common.platformTimeout(15000); } @@ -19,10 +18,14 @@ function isPreBreak(output) { return /Break on start/.test(output) && /1 \(function \(exports/.test(output); } -function startCLI(args, flags = [], spawnOpts = {}) { +function startCLI(args, flags = [], spawnOpts = {}, opts = { randomPort: true }) { let stderrOutput = ''; - const child = - spawn(process.execPath, [...flags, 'inspect', ...args], spawnOpts); + const child = spawn(process.execPath, [ + ...flags, + 'inspect', + ...(opts.randomPort !== false ? ['--port=0'] : []), + ...args, + ], spawnOpts); const outputBuffer = []; function bufferOutput(chunk) { @@ -85,12 +88,12 @@ function startCLI(args, flags = [], spawnOpts = {}) { reject(new Error(message)); } + // Capture stack trace here to show where waitFor was called from when it times out. + const timeoutErr = new Error(`Timeout (${TIMEOUT}) while waiting for ${pattern}`); const timer = setTimeout(() => { tearDown(); - reject(new Error([ - `Timeout (${TIMEOUT}) while waiting for ${pattern}`, - `found: ${this.output}`, - ].join('; '))); + timeoutErr.output = this.output; + reject(timeoutErr); }, TIMEOUT); function tearDown() { @@ -138,6 +141,10 @@ function startCLI(args, flags = [], spawnOpts = {}) { return getOutput(); }, + get stderrOutput() { + return stderrOutput; + }, + get rawOutput() { return outputBuffer.join('').toString(); }, diff --git a/test/js/node/test/common/fixtures.js b/test/js/node/test/common/fixtures.js index 75815b035ba1..1292f01d2a17 100644 --- a/test/js/node/test/common/fixtures.js +++ b/test/js/node/test/common/fixtures.js @@ -7,16 +7,17 @@ const { pathToFileURL } = require('url'); const fixturesDir = path.join(__dirname, '..', 'fixtures'); function fixturesPath(...args) { - return path.join(fixturesDir, ...args); + args.unshift(fixturesDir); + return Reflect.apply(path.join, this, args); } function fixturesFileURL(...args) { - return pathToFileURL(fixturesPath(...args)); + return pathToFileURL(Reflect.apply(fixturesPath, this, args)); } function readFixtureSync(args, enc) { if (Array.isArray(args)) - return fs.readFileSync(fixturesPath(...args), enc); + return fs.readFileSync(Reflect.apply(fixturesPath, this, args), enc); return fs.readFileSync(fixturesPath(args), enc); } diff --git a/test/js/node/test/common/index.js b/test/js/node/test/common/index.js index a4ab5ba15f73..e139f3ac332a 100644 --- a/test/js/node/test/common/index.js +++ b/test/js/node/test/common/index.js @@ -59,6 +59,21 @@ const hasCrypto = Boolean(process.versions.openssl) && const hasSQLite = Boolean(process.versions.sqlite); +const usesSharedLibrary = process.config.variables.node_shared; +// Bun has `bun:ffi` but not Node's `node:ffi`, which is what this gates. +const hasFFI = Boolean(process.config.variables.node_use_ffi); + +// small-icu doesn't support non-English locales +const hasFullICU = (() => { + try { + const january = new Date(9e8); + const spanish = new Intl.DateTimeFormat('es', { month: 'long' }); + return spanish.format(january) === 'enero'; + } catch { + return false; + } +})(); + // Node gates these on build variables (v8_enable_temporal_support and // --localstorage-file). Bun has no equivalent knobs, so feature-detect. const hasTemporal = typeof globalThis.Temporal === 'object' && globalThis.Temporal !== null; @@ -942,6 +957,12 @@ function skipIfSQLiteMissing() { } } +function skipIfFFIMissing() { + if (!hasFFI) { + skip('missing FFI'); + } +} + function getArrayBufferViews(buf) { const { buffer, byteOffset, byteLength } = buf; @@ -1190,12 +1211,30 @@ function expectRequiredModule(mod, expectation, checkESModule = true) { assert.deepStrictEqual(clone, { ...expectation }); } +function expectRequiredTLAError(err) { + const message = /require\(\) cannot be used on an ESM graph with top-level await/; + if (typeof err === 'string') { + assert.match(err, /ERR_REQUIRE_ASYNC_MODULE/); + assert.match(err, message); + } else { + assert.strictEqual(err.code, 'ERR_REQUIRE_ASYNC_MODULE'); + assert.match(err.message, message); + } +} + function sleepSync(ms) { const sab = new SharedArrayBuffer(4); const i32 = new Int32Array(sab); Atomics.wait(i32, 0, 0, ms); } +function resolveBuiltBinary(binary) { + if (isWindows) { + binary += '.exe'; + } + return path.join(path.dirname(process.execPath), binary); +} + const common = { allowGlobals, buildType, @@ -1206,6 +1245,7 @@ const common = { escapePOSIXShell, expectsError, expectRequiredModule, + expectRequiredTLAError, expectWarning, gcUntil, getArrayBufferViews, @@ -1215,6 +1255,8 @@ const common = { getTTYfd, hasIntl, hasCrypto, + hasFFI, + hasFullICU, hasOpenSSL, hasQuic, hasSQLite, @@ -1232,6 +1274,7 @@ const common = { isOpenBSD, isMacOS, isPi, + isRiscv64, isSunOS, isWindows, localIPv6Hosts, @@ -1250,15 +1293,18 @@ const common = { requireNoPackageJSONAbove, hasInspector, runWithInvalidFD, + resolveBuiltBinary, skip, skipIf32Bits, skipIfDumbTerminal, skipIfEslintMissing, skipIfInspectorDisabled, + skipIfFFIMissing, skipIfSQLiteMissing, skipIfWorker, sleepSync, spawnPromisified, + usesSharedLibrary, get enoughTestMem() { return require('os').totalmem() > 0x70000000; /* 1.75 Gb */ diff --git a/test/js/node/test/common/index.mjs b/test/js/node/test/common/index.mjs index 9679b1fd2a7c..03f675c2f0f9 100644 --- a/test/js/node/test/common/index.mjs +++ b/test/js/node/test/common/index.mjs @@ -12,12 +12,15 @@ const { createZeroFilledFile, enoughTestMem, escapePOSIXShell, + expectRequiredTLAError, expectsError, expectWarning, getArrayBufferViews, getBufferSources, getTTYfd, hasCrypto, + hasFFI, + hasFullICU, hasInspector, hasIntl, hasIPv6, @@ -32,6 +35,7 @@ const { isLinux, isLinuxPPCBE, isMainThread, + isRiscv64, isOpenBSD, isMacOS, isSunOS, @@ -48,6 +52,7 @@ const { parseTestMetadata, PIPE, platformTimeout, + resolveBuiltBinary, printSkipMessage, runWithInvalidFD, skip, @@ -55,9 +60,11 @@ const { skipIfDumbTerminal, skipIfEslintMissing, skipIfInspectorDisabled, + skipIfFFIMissing, skipIfSQLiteMissing, sleepSync, spawnPromisified, + usesSharedLibrary, } = common; const getPort = () => common.PORT; @@ -72,6 +79,7 @@ export { createZeroFilledFile, enoughTestMem, escapePOSIXShell, + expectRequiredTLAError, expectsError, expectWarning, getArrayBufferViews, @@ -79,6 +87,8 @@ export { getPort, getTTYfd, hasCrypto, + hasFFI, + hasFullICU, hasInspector, hasIntl, hasIPv6, @@ -93,6 +103,7 @@ export { isLinux, isLinuxPPCBE, isMainThread, + isRiscv64, isOpenBSD, isMacOS, isSunOS, @@ -109,6 +120,7 @@ export { parseTestMetadata, PIPE, platformTimeout, + resolveBuiltBinary, printSkipMessage, runWithInvalidFD, skip, @@ -116,7 +128,9 @@ export { skipIfDumbTerminal, skipIfEslintMissing, skipIfInspectorDisabled, + skipIfFFIMissing, skipIfSQLiteMissing, sleepSync, spawnPromisified, + usesSharedLibrary, }; diff --git a/test/js/node/test/common/inspector-helper.js b/test/js/node/test/common/inspector-helper.js index 864538f245e2..895e4c779726 100644 --- a/test/js/node/test/common/inspector-helper.js +++ b/test/js/node/test/common/inspector-helper.js @@ -6,7 +6,7 @@ const http = require('http'); const fixtures = require('../common/fixtures'); const { spawn } = require('child_process'); const { URL, pathToFileURL } = require('url'); -const { EventEmitter } = require('events'); +const { EventEmitter, once } = require('events'); const _MAINSCRIPT = fixtures.path('loop.js'); const DEBUG = false; @@ -544,6 +544,34 @@ function fires(promise, error, timeoutMs) { ]); } +/** + * When waiting for inspector events, there might be no handles on the event + * loop, and leads to process exits. + * + * This function provides a utility to wait until a inspector event for a certain + * time. + * @returns {Promise} + */ +function waitUntil(session, eventName, timeout = 1000) { + const resolvers = Promise.withResolvers(); + const timer = setTimeout(() => { + resolvers.reject(new Error(`Wait for inspector event ${eventName} timed out`)); + }, timeout); + + once(session, eventName) + .then((res) => { + resolvers.resolve(res); + clearTimeout(timer); + }, (error) => { + // This should never happen. + resolvers.reject(error); + clearTimeout(timer); + }); + + return resolvers.promise; +} + module.exports = { NodeInstance, + waitUntil, }; diff --git a/test/js/node/test/common/internet.js b/test/js/node/test/common/internet.js index 51f18aeb4470..411917893d22 100644 --- a/test/js/node/test/common/internet.js +++ b/test/js/node/test/common/internet.js @@ -38,6 +38,8 @@ const addresses = { CNAME_HOST: 'blog.nodejs.org', // A host with NS records registered NS_HOST: 'nodejs.org', + // A host with TLSA records registered + TLSA_HOST: '_443._tcp.fedoraproject.org', // A host with TXT records registered TXT_HOST: 'nodejs.org', // An accessible IPv4 DNS server diff --git a/test/js/node/test/common/test-error-reporter.js b/test/js/node/test/common/test-error-reporter.js new file mode 100644 index 000000000000..d6db28e675ad --- /dev/null +++ b/test/js/node/test/common/test-error-reporter.js @@ -0,0 +1,41 @@ +'use strict'; +const { relative } = require('node:path'); +const { inspect } = require('node:util'); +const cwd = process.cwd(); + +module.exports = async function* errorReporter(source) { + for await (const event of source) { + if (event.type === 'test:fail') { + const { name, details, line, column, file } = event.data; + let { error } = details; + + if (error?.failureType === 'subtestsFailed') { + // In the interest of keeping things concise, skip failures that are + // only due to nested failures. + continue; + } + + if (error?.code === 'ERR_TEST_FAILURE') { + error = error.cause; + } + + const output = [ + `Test failure: '${name}'`, + ]; + + if (file) { + output.push(`Location: ${relative(cwd, file)}:${line}:${column}`); + } + + output.push(inspect(error)); + output.push('\n'); + yield output.join('\n'); + + if (process.env.FAIL_FAST) { + yield `\nBailing on failed test: ${event.data.name}\n`; + process.exitCode = 1; + process.emit('SIGINT'); + } + } + } +}; diff --git a/test/js/node/test/common/tmpdir.js b/test/js/node/test/common/tmpdir.js index f1f06818dc46..d56a73311059 100644 --- a/test/js/node/test/common/tmpdir.js +++ b/test/js/node/test/common/tmpdir.js @@ -5,17 +5,28 @@ const fs = require('fs'); const path = require('path'); const { pathToFileURL } = require('url'); const { isMainThread } = require('worker_threads'); +const isUnixLike = process.platform !== 'win32'; +let escapePOSIXShell; function rmSync(pathname, useSpawn) { if (useSpawn) { - const escapedPath = pathname.replaceAll('\\', '\\\\'); - spawnSync( - process.execPath, - [ - '-e', - `require("fs").rmSync("${escapedPath}", { maxRetries: 3, recursive: true, force: true });`, - ], - ); + if (isUnixLike) { + escapePOSIXShell ??= require('./index.js').escapePOSIXShell; + for (let i = 0; i < 3; i++) { + const { status } = spawnSync(...escapePOSIXShell`rm -rf "${pathname}"`); + if (status === 0) { + break; + } + } + } else { + spawnSync( + process.execPath, + [ + '-e', + `fs.rmSync(${JSON.stringify(pathname)}, { maxRetries: 3, recursive: true, force: true });`, + ], + ); + } } else { fs.rmSync(pathname, { maxRetries: 3, recursive: true, force: true }); } @@ -28,7 +39,7 @@ const testRoot = process.env.NODE_TEST_DIR ? // gets tools to ignore it by default or by simple rules, especially eslint. const tmpdirName = '.tmp.' + (process.env.TEST_SERIAL_ID || process.env.TEST_THREAD_ID || '0'); -const tmpPath = path.join(testRoot, tmpdirName); +let tmpPath = path.join(testRoot, tmpdirName); let firstRefresh = true; function refresh(useSpawn = false) { @@ -89,7 +100,13 @@ function fileURL(...paths) { module.exports = { fileURL, hasEnoughSpace, - path: tmpPath, refresh, resolve, + + get path() { + return tmpPath; + }, + set path(newPath) { + tmpPath = path.resolve(newPath); + }, }; diff --git a/test/js/node/test/common/v8-max-heap-size-option.js b/test/js/node/test/common/v8-max-heap-size-option.js new file mode 100644 index 000000000000..4487b011a97c --- /dev/null +++ b/test/js/node/test/common/v8-max-heap-size-option.js @@ -0,0 +1,49 @@ +'use strict'; + +const assert = require('assert'); +const { spawnSync } = require('child_process'); +const path = require('path'); +const fs = require('fs'); +const tmpdir = require('./tmpdir'); + +const testScript = ` + const v8 = require('v8'); + const stats = v8.getHeapStatistics(); + const maxHeapSizeMB = Math.round(stats.heap_size_limit / 1024 / 1024); + console.log(maxHeapSizeMB); +`; + +tmpdir.refresh(); +const scriptPath = path.join(tmpdir.path, 'heap-limit-test.js'); +fs.writeFileSync(scriptPath, testScript); + +const child = spawnSync( + process.execPath, + [scriptPath], + { + encoding: 'utf8', + env: { + ...process.env, + NODE_OPTIONS: '--max-heap-size=750', + }, + }, +); + +assert.strictEqual( + child.status, + 0, + [ + `Child process did not exit cleanly.`, + ` Exit code: ${child.status}`, + child.stderr ? ` Stderr: ${child.stderr.toString()}` : '', + child.stdout ? ` Stdout: ${child.stdout.toString()}` : '', + ].filter(Boolean).join('\n'), +); +const output = child.stdout.trim(); +const heapLimit = Number(output); + +assert.strictEqual( + heapLimit, + 750, + `max heap size is ${heapLimit}MB, expected 750MB`, +); diff --git a/test/js/node/test/common/websocket-server.js b/test/js/node/test/common/websocket-server.js new file mode 100644 index 000000000000..f120d3bf71bb --- /dev/null +++ b/test/js/node/test/common/websocket-server.js @@ -0,0 +1,111 @@ +'use strict'; +const common = require('./index'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const http = require('http'); +const crypto = require('crypto'); + +class WebSocketServer { + constructor({ + port = 0, + server, + customHandleUpgradeHeaders = [], + }) { + this.port = port; + this.server = server || http.createServer(); + this.clients = new Set(); + this.customHandleUpgradeHeaders = customHandleUpgradeHeaders; + + this.server.on('upgrade', this.handleUpgrade.bind(this)); + } + + start() { + return new Promise((resolve) => { + this.server.listen(this.port, () => { + this.port = this.server.address().port; + resolve(); + }); + }).catch((err) => { + console.error('Failed to start WebSocket server:', err); + }); + } + + handleUpgrade(req, socket, head) { + const key = req.headers['sec-websocket-key']; + const acceptKey = this.generateAcceptValue(key); + const responseHeaders = [ + 'HTTP/1.1 101 Switching Protocols', + 'Upgrade: websocket', + 'Connection: Upgrade', + `Sec-WebSocket-Accept: ${acceptKey}`, + ...this.customHandleUpgradeHeaders, + ]; + + socket.write(responseHeaders.join('\r\n') + '\r\n\r\n'); + this.clients.add(socket); + + socket.on('data', (buffer) => { + const opcode = buffer[0] & 0x0f; + + if (opcode === 0x8) { + // Send a minimal close frame in response: + socket.write(Buffer.from([0x88, 0x00])); + socket.end(); + this.clients.delete(socket); + return; + } + + socket.write(this.encodeMessage('Hello from server!')); + }); + + socket.on('close', () => { + this.clients.delete(socket); + }); + + socket.on('error', (err) => { + console.error('Socket error:', err); + this.clients.delete(socket); + }); + } + + generateAcceptValue(secWebSocketKey) { + return crypto + .createHash('sha1') + .update(secWebSocketKey + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', 'binary') + .digest('base64'); + } + + decodeMessage(buffer) { + const secondByte = buffer[1]; + const length = secondByte & 127; + const maskStart = 2; + const dataStart = maskStart + 4; + const masks = buffer.slice(maskStart, dataStart); + const data = buffer.slice(dataStart, dataStart + length); + const result = Buffer.alloc(length); + + for (let i = 0; i < length; i++) { + result[i] = data[i] ^ masks[i % 4]; + } + + return result.toString(); + } + + encodeMessage(message) { + const msgBuffer = Buffer.from(message); + const length = msgBuffer.length; + const frame = [0x81]; + + if (length < 126) { + frame.push(length); + } else if (length < 65536) { + frame.push(126, (length >> 8) & 0xff, length & 0xff); + } else { + throw new Error('Message too long'); + } + + return Buffer.concat([Buffer.from(frame), msgBuffer]); + } +} + +module.exports = WebSocketServer; diff --git a/test/js/node/test/parallel/test-als-defaultvalue.js b/test/js/node/test/parallel/test-als-defaultvalue.js index 2565983ed6b0..5b5b43b57a72 100644 --- a/test/js/node/test/parallel/test-als-defaultvalue.js +++ b/test/js/node/test/parallel/test-als-defaultvalue.js @@ -1,18 +1,21 @@ -"use strict"; +// Flags: --async-context-frame +'use strict'; -require("../common"); +require('../common'); -const { AsyncLocalStorage } = require("async_hooks"); +const { + AsyncLocalStorage, +} = require('async_hooks'); -const assert = require("assert"); +const assert = require('assert'); // ============================================================================ // The defaultValue option const als1 = new AsyncLocalStorage(); assert.strictEqual(als1.getStore(), undefined); -const als2 = new AsyncLocalStorage({ defaultValue: "default" }); -assert.strictEqual(als2.getStore(), "default"); +const als2 = new AsyncLocalStorage({ defaultValue: 'default' }); +assert.strictEqual(als2.getStore(), 'default'); const als3 = new AsyncLocalStorage({ defaultValue: 42 }); assert.strictEqual(als3.getStore(), 42); @@ -21,14 +24,14 @@ const als4 = new AsyncLocalStorage({ defaultValue: null }); assert.strictEqual(als4.getStore(), null); assert.throws(() => new AsyncLocalStorage(null), { - code: "ERR_INVALID_ARG_TYPE", + code: 'ERR_INVALID_ARG_TYPE', }); // ============================================================================ // The name option -const als5 = new AsyncLocalStorage({ name: "test" }); -assert.strictEqual(als5.name, "test"); +const als5 = new AsyncLocalStorage({ name: 'test' }); +assert.strictEqual(als5.name, 'test'); const als6 = new AsyncLocalStorage(); -assert.strictEqual(als6.name, ""); +assert.strictEqual(als6.name, ''); diff --git a/test/js/node/test/parallel/test-assert-async.js b/test/js/node/test/parallel/test-assert-async.js index bcf3d55622b8..3fc7e3c0a0ea 100644 --- a/test/js/node/test/parallel/test-assert-async.js +++ b/test/js/node/test/parallel/test-assert-async.js @@ -85,7 +85,7 @@ const invalidThenableFunc = () => { } { - const handler = (err) => { + const handler = common.mustCallAtLeast((err) => { assert(err instanceof assert.AssertionError, `${err.name} is not instance of AssertionError`); assert.strictEqual(err.code, 'ERR_ASSERTION'); @@ -94,7 +94,7 @@ const invalidThenableFunc = () => { assert.strictEqual(err.operator, 'rejects'); assert.ok(!err.stack.includes('at Function.rejects')); return true; - }; + }); let promise = assert.rejects(async () => {}, common.mustNotCall()); promises.push(assert.rejects(promise, common.mustCall(handler))); @@ -132,14 +132,14 @@ promises.push(assert.rejects( )); { - const handler = (generated, actual, err) => { + const handler = common.mustCallAtLeast((generated, actual, err) => { assert.strictEqual(err.generatedMessage, generated); assert.strictEqual(err.code, 'ERR_ASSERTION'); assert.strictEqual(err.actual, actual); assert.strictEqual(err.operator, 'rejects'); assert.match(err.stack, /rejects/); return true; - }; + }); const err = new Error(); promises.push(assert.rejects( assert.rejects(Promise.reject(null), { code: 'FOO' }), @@ -192,14 +192,14 @@ promises.push(assert.rejects( }) ); - const handler1 = (err) => { + const handler1 = common.mustCallAtLeast((err) => { assert(err instanceof assert.AssertionError, `${err.name} is not instance of AssertionError`); assert.strictEqual(err.code, 'ERR_ASSERTION'); assert.strictEqual(err.message, 'Failed'); return true; - }; - const handler2 = (err) => { + }); + const handler2 = common.mustCallAtLeast((err) => { assert(err instanceof assert.AssertionError, `${err.name} is not instance of AssertionError`); assert.strictEqual(err.code, 'ERR_ASSERTION'); @@ -209,7 +209,7 @@ promises.push(assert.rejects( assert.ok(err.stack); assert.ok(!err.stack.includes('at Function.doesNotReject')); return true; - }; + }); const rejectingFn = async () => assert.fail(); diff --git a/test/js/node/test/parallel/test-assert-checktag.js b/test/js/node/test/parallel/test-assert-checktag.js index b86a1bde7f09..b1c3660ab4a6 100644 --- a/test/js/node/test/parallel/test-assert-checktag.js +++ b/test/js/node/test/parallel/test-assert-checktag.js @@ -1,5 +1,5 @@ 'use strict'; -const { hasCrypto } = require('../common'); +const { hasCrypto, hasLocalStorage } = require('../common'); const { test } = require('node:test'); const assert = require('assert'); @@ -12,7 +12,7 @@ const assert = require('assert'); if (process.stdout.isTTY) process.env.NODE_DISABLE_COLORS = '1'; -test('', { skip: !hasCrypto }, () => { +test({ skip: !hasCrypto || !hasLocalStorage }, () => { // See https://github.com/nodejs/node/issues/10258 { const date = new Date('2016'); diff --git a/test/js/node/test/parallel/test-assert-deep-with-error.js b/test/js/node/test/parallel/test-assert-deep-with-error.js index f6bc5c6359cf..8cfb9ce1bf90 100644 --- a/test/js/node/test/parallel/test-assert-deep-with-error.js +++ b/test/js/node/test/parallel/test-assert-deep-with-error.js @@ -3,6 +3,13 @@ require('../common'); const assert = require('assert'); const { test } = require('node:test'); +// Disable colored output to prevent color codes from breaking assertion +// message comparisons. This should only be an issue when process.stdout +// is a TTY. +if (process.stdout.isTTY) { + process.env.NODE_DISABLE_COLORS = '1'; +} + const defaultStartMessage = 'Expected values to be strictly deep-equal:\n' + '+ actual - expected\n' + '\n'; diff --git a/test/js/node/test/parallel/test-assert-typedarray-deepequal.js b/test/js/node/test/parallel/test-assert-typedarray-deepequal.js index 7fb18c1886ba..0ca174ea96c3 100644 --- a/test/js/node/test/parallel/test-assert-typedarray-deepequal.js +++ b/test/js/node/test/parallel/test-assert-typedarray-deepequal.js @@ -20,6 +20,7 @@ suite('equalArrayPairs', () => { [new Int8Array(1e5), new Int8Array(1e5)], [new Int16Array(1e5), new Int16Array(1e5)], [new Int32Array(1e5), new Int32Array(1e5)], + [new Float16Array(1e5), new Float16Array(1e5)], [new Float32Array(1e5), new Float32Array(1e5)], [new Float64Array(1e5), new Float64Array(1e5)], [new Float32Array([+0.0]), new Float32Array([+0.0])], @@ -34,13 +35,19 @@ suite('equalArrayPairs', () => { test('', () => { // eslint-disable-next-line no-restricted-properties assert.deepEqual(arrayPair[0], arrayPair[1]); + // eslint-disable-next-line no-restricted-properties + assert.deepEqual(arrayPair[1], arrayPair[0]); assert.deepStrictEqual(arrayPair[0], arrayPair[1]); + assert.deepStrictEqual(arrayPair[1], arrayPair[0]); + assert.partialDeepStrictEqual(arrayPair[0], arrayPair[1]); + assert.partialDeepStrictEqual(arrayPair[1], arrayPair[0]); }); } }); suite('looseEqualArrayPairs', () => { const looseEqualArrayPairs = [ + [new Float16Array([+0.0]), new Float16Array([-0.0])], [new Float32Array([+0.0]), new Float32Array([-0.0])], [new Float64Array([+0.0]), new Float64Array([-0.0])], ]; @@ -49,10 +56,24 @@ suite('looseEqualArrayPairs', () => { test('', () => { // eslint-disable-next-line no-restricted-properties assert.deepEqual(arrayPair[0], arrayPair[1]); + // eslint-disable-next-line no-restricted-properties + assert.deepEqual(arrayPair[1], arrayPair[0]); assert.throws( makeBlock(assert.deepStrictEqual, arrayPair[0], arrayPair[1]), assert.AssertionError ); + assert.throws( + makeBlock(assert.deepStrictEqual, arrayPair[1], arrayPair[0]), + assert.AssertionError + ); + assert.throws( + makeBlock(assert.partialDeepStrictEqual, arrayPair[0], arrayPair[1]), + assert.AssertionError + ); + assert.throws( + makeBlock(assert.partialDeepStrictEqual, arrayPair[1], arrayPair[0]), + assert.AssertionError + ); }); } }); @@ -63,7 +84,7 @@ suite('notEqualArrayPairs', () => { [new Int16Array(256), new Uint16Array(256)], [new Int16Array([256]), new Uint16Array([256])], [new Float64Array([+0.0]), new Float32Array([-0.0])], - [new Uint8Array(2), new Uint8Array(3)], + [new Uint8Array(2), new Uint8Array(3), 'unequal length'], [new Uint8Array([1, 2, 3]), new Uint8Array([4, 5, 6])], [new Uint8ClampedArray([300, 2, 3]), new Uint8Array([300, 2, 3])], [new Uint16Array([2]), new Uint16Array([3])], @@ -71,16 +92,18 @@ suite('notEqualArrayPairs', () => { [new Int16Array([0]), new Uint16Array([256])], [new Int16Array([-256]), new Uint16Array([0xff00])], // same bits [new Int32Array([-256]), new Uint32Array([0xffffff00])], // ditto + [new Float16Array([0.1]), new Float16Array([0.0])], + [new Float16Array([0.1]), new Float16Array([0.1, 0.2]), 'unequal length'], [new Float32Array([0.1]), new Float32Array([0.0])], - [new Float32Array([0.1]), new Float32Array([0.1, 0.2])], + [new Float32Array([0.1]), new Float32Array([0.1, 0.2]), 'unequal length'], [new Float64Array([0.1]), new Float64Array([0.0])], [new Uint8Array([1, 2, 3]).buffer, new Uint8Array([4, 5, 6]).buffer], [ new Uint8Array(new SharedArrayBuffer(3)).fill(1).buffer, new Uint8Array(new SharedArrayBuffer(3)).fill(2).buffer, ], - [new ArrayBuffer(2), new ArrayBuffer(3)], - [new SharedArrayBuffer(2), new SharedArrayBuffer(3)], + [new ArrayBuffer(2), new ArrayBuffer(3), 'unequal length'], + [new SharedArrayBuffer(2), new SharedArrayBuffer(3), 'unequal length'], [new ArrayBuffer(2), new SharedArrayBuffer(3)], [ new Uint8Array(new ArrayBuffer(3)).fill(1).buffer, @@ -97,14 +120,31 @@ suite('notEqualArrayPairs', () => { makeBlock(assert.deepEqual, arrayPair[0], arrayPair[1]), assert.AssertionError ); + assert.throws( + // eslint-disable-next-line no-restricted-properties + makeBlock(assert.deepEqual, arrayPair[1], arrayPair[0]), + assert.AssertionError + ); assert.throws( makeBlock(assert.deepStrictEqual, arrayPair[0], arrayPair[1]), assert.AssertionError ); + assert.throws( + makeBlock(assert.deepStrictEqual, arrayPair[1], arrayPair[0]), + assert.AssertionError + ); assert.throws( makeBlock(assert.partialDeepStrictEqual, arrayPair[0], arrayPair[1]), assert.AssertionError ); + if (arrayPair[2]) { + assert.partialDeepStrictEqual(arrayPair[1], arrayPair[0]); + } else { + assert.throws( + makeBlock(assert.partialDeepStrictEqual, arrayPair[1], arrayPair[0]), + assert.AssertionError + ); + } }); } }); diff --git a/test/js/node/test/parallel/test-async-hooks-recursive-stack-runInAsyncScope.js b/test/js/node/test/parallel/test-async-hooks-recursive-stack-runInAsyncScope.js index bc4ac86e7f1c..d0d5ee76e9d1 100644 --- a/test/js/node/test/parallel/test-async-hooks-recursive-stack-runInAsyncScope.js +++ b/test/js/node/test/parallel/test-async-hooks-recursive-stack-runInAsyncScope.js @@ -1,5 +1,5 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const async_hooks = require('async_hooks'); @@ -7,14 +7,14 @@ const async_hooks = require('async_hooks'); function recurse(n) { const a = new async_hooks.AsyncResource('foobar'); - a.runInAsyncScope(() => { + a.runInAsyncScope(common.mustCall(() => { assert.strictEqual(a.asyncId(), async_hooks.executionAsyncId()); assert.strictEqual(a.triggerAsyncId(), async_hooks.triggerAsyncId()); if (n >= 0) recurse(n - 1); assert.strictEqual(a.asyncId(), async_hooks.executionAsyncId()); assert.strictEqual(a.triggerAsyncId(), async_hooks.triggerAsyncId()); - }); + })); } recurse(1000); diff --git a/test/js/node/test/parallel/test-async-local-storage-contexts.js b/test/js/node/test/parallel/test-async-local-storage-contexts.js index 9a6327133794..b63d383fecc4 100644 --- a/test/js/node/test/parallel/test-async-local-storage-contexts.js +++ b/test/js/node/test/parallel/test-async-local-storage-contexts.js @@ -1,6 +1,6 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const vm = require('vm'); const { AsyncLocalStorage } = require('async_hooks'); @@ -26,10 +26,10 @@ vm.runInContext(` const storage = new AsyncLocalStorage(); async function test() { - return storage.run({ test: 'main context' }, async () => { + return storage.run({ test: 'main context' }, common.mustCall(async () => { assert.strictEqual(storage.getStore().test, 'main context'); await 42; assert.strictEqual(storage.getStore().test, 'main context'); - }); + })); } test(); diff --git a/test/js/node/test/parallel/test-async-local-storage-snapshot.js b/test/js/node/test/parallel/test-async-local-storage-snapshot.js index 63e47ba3ce0a..169da60c3a32 100644 --- a/test/js/node/test/parallel/test-async-local-storage-snapshot.js +++ b/test/js/node/test/parallel/test-async-local-storage-snapshot.js @@ -1,7 +1,7 @@ 'use strict'; const common = require('../common'); -const { strictEqual } = require('assert'); +const assert = require('assert'); const { AsyncLocalStorage } = require('async_hooks'); const asyncLocalStorage = new AsyncLocalStorage(); @@ -13,4 +13,4 @@ const result = return asyncLocalStorage.getStore(); }); })); -strictEqual(result, 123); +assert.strictEqual(result, 123); diff --git a/test/js/node/test/parallel/test-blocklist-clone.js b/test/js/node/test/parallel/test-blocklist-clone.js index 4264b36f54ca..ea6471c7df87 100644 --- a/test/js/node/test/parallel/test-blocklist-clone.js +++ b/test/js/node/test/parallel/test-blocklist-clone.js @@ -6,10 +6,7 @@ const { BlockList, } = require('net'); -const { - ok, - notStrictEqual, -} = require('assert'); +const assert = require('assert'); const blocklist = new BlockList(); blocklist.addAddress('123.123.123.123'); @@ -17,13 +14,13 @@ blocklist.addAddress('123.123.123.123'); const mc = new MessageChannel(); mc.port1.onmessage = common.mustCall(({ data }) => { - notStrictEqual(data, blocklist); - ok(data.check('123.123.123.123')); - ok(!data.check('123.123.123.124')); + assert.notStrictEqual(data, blocklist); + assert.ok(data.check('123.123.123.123')); + assert.ok(!data.check('123.123.123.124')); data.addAddress('123.123.123.124'); - ok(blocklist.check('123.123.123.124')); - ok(data.check('123.123.123.124')); + assert.ok(blocklist.check('123.123.123.124')); + assert.ok(data.check('123.123.123.124')); mc.port1.close(); }); diff --git a/test/js/node/test/parallel/test-btoa-atob.js b/test/js/node/test/parallel/test-btoa-atob.js index abf05adeef10..a2c8d9e3134c 100644 --- a/test/js/node/test/parallel/test-btoa-atob.js +++ b/test/js/node/test/parallel/test-btoa-atob.js @@ -2,37 +2,37 @@ require('../common'); -const { strictEqual, throws } = require('assert'); +const assert = require('assert'); const buffer = require('buffer'); // Exported on the global object -strictEqual(globalThis.atob, buffer.atob); -strictEqual(globalThis.btoa, buffer.btoa); +assert.strictEqual(globalThis.atob, buffer.atob); +assert.strictEqual(globalThis.btoa, buffer.btoa); // Throws type error on no argument passed -throws(() => buffer.atob(), /TypeError/); -throws(() => buffer.btoa(), /TypeError/); +assert.throws(() => buffer.atob(), /TypeError/); +assert.throws(() => buffer.btoa(), /TypeError/); -strictEqual(atob(' '), ''); -strictEqual(atob(' Y\fW\tJ\njZ A=\r= '), 'abcd'); +assert.strictEqual(atob(' '), ''); +assert.strictEqual(atob(' Y\fW\tJ\njZ A=\r= '), 'abcd'); -strictEqual(atob(null), '\x9Eée'); -strictEqual(atob(NaN), '5£'); -strictEqual(atob(Infinity), '"wâ\x9E+r'); -strictEqual(atob(true), '¶»\x9E'); -strictEqual(atob(1234), '×mø'); -strictEqual(atob([]), ''); -strictEqual(atob({ toString: () => '' }), ''); -strictEqual(atob({ [Symbol.toPrimitive]: () => '' }), ''); +assert.strictEqual(atob(null), '\x9Eée'); +assert.strictEqual(atob(NaN), '5£'); +assert.strictEqual(atob(Infinity), '"wâ\x9E+r'); +assert.strictEqual(atob(true), '¶»\x9E'); +assert.strictEqual(atob(1234), '×mø'); +assert.strictEqual(atob([]), ''); +assert.strictEqual(atob({ toString: () => '' }), ''); +assert.strictEqual(atob({ [Symbol.toPrimitive]: () => '' }), ''); -throws(() => atob(Symbol()), /TypeError/); +assert.throws(() => atob(Symbol()), /TypeError/); [ undefined, false, () => {}, {}, [1], 0, 1, 0n, 1n, -Infinity, 'a', 'a\n\n\n', '\ra\r\r', ' a ', '\t\t\ta', 'a\f\f\f', '\ta\r \n\f', ].forEach((value) => // See #2 - https://html.spec.whatwg.org/multipage/webappapis.html#dom-atob - throws(() => atob(value), { + assert.throws(() => atob(value), { constructor: DOMException, name: 'InvalidCharacterError', code: 5, diff --git a/test/js/node/test/parallel/test-child-process-can-write-to-stdout.js b/test/js/node/test/parallel/test-child-process-can-write-to-stdout.js index 069e07fb1602..68e1bff877ff 100644 --- a/test/js/node/test/parallel/test-child-process-can-write-to-stdout.js +++ b/test/js/node/test/parallel/test-child-process-can-write-to-stdout.js @@ -2,7 +2,7 @@ // Tests that a spawned child process can write to stdout without throwing. // See https://github.com/nodejs/node-v0.x-archive/issues/1899. -require('../common'); +const common = require('../common'); const fixtures = require('../common/fixtures'); const assert = require('assert'); const spawn = require('child_process').spawn; @@ -16,7 +16,7 @@ child.stdout.on('data', function(data) { output += data; }); -child.on('exit', function(code, signal) { +child.on('exit', common.mustCall((code) => { assert.strictEqual(code, 0); assert.strictEqual(output, 'hello, world!\n'); -}); +})); diff --git a/test/js/node/test/parallel/test-child-process-cwd.js b/test/js/node/test/parallel/test-child-process-cwd.js index e876361b167f..847c666a9077 100644 --- a/test/js/node/test/parallel/test-child-process-cwd.js +++ b/test/js/node/test/parallel/test-child-process-cwd.js @@ -32,7 +32,7 @@ const { spawn } = require('child_process'); // - whether the child pid is undefined or number, // - whether the exit code equals expectCode, // - optionally whether the trimmed stdout result matches expectData -function testCwd(options, expectPidType, expectCode = 0, expectData) { +function testCwd(options, expectPidType, expectCode = 0, expectData, shouldCallExit = true) { const child = spawn(...common.pwdCommand, options); assert.strictEqual(typeof child.pid, expectPidType); @@ -47,9 +47,9 @@ function testCwd(options, expectPidType, expectCode = 0, expectData) { // Can't assert callback, as stayed in to API: // _The 'exit' event may or may not fire after an error has occurred._ - child.on('exit', function(code, signal) { + child.on('exit', shouldCallExit ? common.mustCall((code) => { assert.strictEqual(code, expectCode); - }); + }) : common.mustNotCall()); child.on('close', common.mustCall(function() { if (expectData) { @@ -68,7 +68,7 @@ function testCwd(options, expectPidType, expectCode = 0, expectData) { // Assume does-not-exist doesn't exist, expect exitCode=-1 and errno=ENOENT { - testCwd({ cwd: 'does-not-exist' }, 'undefined', -1) + testCwd({ cwd: 'does-not-exist' }, 'undefined', -1, undefined, false) .on('error', common.mustCall(function(e) { assert.strictEqual(e.code, 'ENOENT'); })); diff --git a/test/js/node/test/parallel/test-child-process-disconnect.js b/test/js/node/test/parallel/test-child-process-disconnect.js index fb8a2dd0ea22..0e4f37ae61d5 100644 --- a/test/js/node/test/parallel/test-child-process-disconnect.js +++ b/test/js/node/test/parallel/test-child-process-disconnect.js @@ -30,13 +30,13 @@ if (process.argv[2] === 'child') { // Check that the 'disconnect' event is deferred to the next event loop tick. const disconnect = process.disconnect; - process.disconnect = function() { + process.disconnect = common.mustCall(function() { disconnect.apply(this, arguments); // If the event is emitted synchronously, we're too late by now. process.once('disconnect', common.mustCall(disconnectIsNotAsync)); // The funky function name makes it show up legible in mustCall errors. function disconnectIsNotAsync() {} - }; + }); const server = net.createServer(); @@ -81,13 +81,13 @@ if (process.argv[2] === 'child') { child.on('exit', common.mustCall()); // When child is listening - child.on('message', function(obj) { + child.on('message', common.mustCallAtLeast((obj) => { if (obj && obj.msg === 'ready') { // Connect to child using TCP to know if disconnect was emitted const socket = net.connect(obj.port); - socket.on('data', function(data) { + socket.on('data', common.mustCallAtLeast((data) => { data = data.toString(); // Ready to be disconnected @@ -103,10 +103,10 @@ if (process.argv[2] === 'child') { // 'disconnect' is emitted childFlag = (data === 'true'); - }); + })); } - }); + })); process.on('exit', function() { assert.strictEqual(childFlag, false); diff --git a/test/js/node/test/parallel/test-child-process-exec-encoding.js b/test/js/node/test/parallel/test-child-process-exec-encoding.js index 059e300e4e76..21ab207fca8c 100644 --- a/test/js/node/test/parallel/test-child-process-exec-encoding.js +++ b/test/js/node/test/parallel/test-child-process-exec-encoding.js @@ -22,28 +22,28 @@ if (process.argv[2] === 'child') { } // Test default encoding, which should be utf8. - run({}, (stdout, stderr) => { + run({}, common.mustCall((stdout, stderr) => { assert.strictEqual(typeof stdout, 'string'); assert.strictEqual(typeof stderr, 'string'); assert.strictEqual(stdout, expectedStdout); assert.strictEqual(stderr, expectedStderr); - }); + })); // Test explicit utf8 encoding. - run({ encoding: 'utf8' }, (stdout, stderr) => { + run({ encoding: 'utf8' }, common.mustCall((stdout, stderr) => { assert.strictEqual(typeof stdout, 'string'); assert.strictEqual(typeof stderr, 'string'); assert.strictEqual(stdout, expectedStdout); assert.strictEqual(stderr, expectedStderr); - }); + })); // Test cases that result in buffer encodings. [undefined, null, 'buffer', 'invalid'].forEach((encoding) => { - run({ encoding }, (stdout, stderr) => { + run({ encoding }, common.mustCall((stdout, stderr) => { assert(stdout instanceof Buffer); assert(stdout instanceof Buffer); assert.strictEqual(stdout.toString(), expectedStdout); assert.strictEqual(stderr.toString(), expectedStderr); - }); + })); }); } diff --git a/test/js/node/test/parallel/test-child-process-flush-stdio.js b/test/js/node/test/parallel/test-child-process-flush-stdio.js index 7b9a2a049cb2..37e63e64990e 100644 --- a/test/js/node/test/parallel/test-child-process-flush-stdio.js +++ b/test/js/node/test/parallel/test-child-process-flush-stdio.js @@ -17,7 +17,7 @@ p.on('close', common.mustCall((code, signal) => { p.stdout.read(); -const spawnWithReadable = () => { +const spawnWithReadable = common.mustCall(() => { const buffer = []; const p = cp.spawn('echo', ['123'], opts); p.on('close', common.mustCall((code, signal) => { @@ -30,4 +30,4 @@ const spawnWithReadable = () => { while ((buf = p.stdout.read()) !== null) buffer.push(buf); }); -}; +}); diff --git a/test/js/node/test/parallel/test-child-process-fork-abort-signal.js b/test/js/node/test/parallel/test-child-process-fork-abort-signal.js index b963306fb1be..1d170134f715 100644 --- a/test/js/node/test/parallel/test-child-process-fork-abort-signal.js +++ b/test/js/node/test/parallel/test-child-process-fork-abort-signal.js @@ -1,7 +1,7 @@ 'use strict'; const { mustCall, mustNotCall } = require('../common'); -const { strictEqual } = require('assert'); +const assert = require('assert'); const fixtures = require('../common/fixtures'); const { fork } = require('child_process'); @@ -13,11 +13,11 @@ const { fork } = require('child_process'); signal }); cp.on('exit', mustCall((code, killSignal) => { - strictEqual(code, null); - strictEqual(killSignal, 'SIGTERM'); + assert.strictEqual(code, null); + assert.strictEqual(killSignal, 'SIGTERM'); })); cp.on('error', mustCall((err) => { - strictEqual(err.name, 'AbortError'); + assert.strictEqual(err.name, 'AbortError'); })); process.nextTick(() => ac.abort()); } @@ -30,13 +30,13 @@ const { fork } = require('child_process'); signal }); cp.on('exit', mustCall((code, killSignal) => { - strictEqual(code, null); - strictEqual(killSignal, 'SIGTERM'); + assert.strictEqual(code, null); + assert.strictEqual(killSignal, 'SIGTERM'); })); cp.on('error', mustCall((err) => { - strictEqual(err.name, 'AbortError'); - strictEqual(err.cause.name, 'Error'); - strictEqual(err.cause.message, 'boom'); + assert.strictEqual(err.name, 'AbortError'); + assert.strictEqual(err.cause.name, 'Error'); + assert.strictEqual(err.cause.message, 'boom'); })); process.nextTick(() => ac.abort(new Error('boom'))); } @@ -48,11 +48,11 @@ const { fork } = require('child_process'); signal }); cp.on('exit', mustCall((code, killSignal) => { - strictEqual(code, null); - strictEqual(killSignal, 'SIGTERM'); + assert.strictEqual(code, null); + assert.strictEqual(killSignal, 'SIGTERM'); })); cp.on('error', mustCall((err) => { - strictEqual(err.name, 'AbortError'); + assert.strictEqual(err.name, 'AbortError'); })); } @@ -63,13 +63,13 @@ const { fork } = require('child_process'); signal }); cp.on('exit', mustCall((code, killSignal) => { - strictEqual(code, null); - strictEqual(killSignal, 'SIGTERM'); + assert.strictEqual(code, null); + assert.strictEqual(killSignal, 'SIGTERM'); })); cp.on('error', mustCall((err) => { - strictEqual(err.name, 'AbortError'); - strictEqual(err.cause.name, 'Error'); - strictEqual(err.cause.message, 'boom'); + assert.strictEqual(err.name, 'AbortError'); + assert.strictEqual(err.cause.name, 'Error'); + assert.strictEqual(err.cause.message, 'boom'); })); } @@ -81,11 +81,11 @@ const { fork } = require('child_process'); killSignal: 'SIGKILL', }); cp.on('exit', mustCall((code, killSignal) => { - strictEqual(code, null); - strictEqual(killSignal, 'SIGKILL'); + assert.strictEqual(code, null); + assert.strictEqual(killSignal, 'SIGKILL'); })); cp.on('error', mustCall((err) => { - strictEqual(err.name, 'AbortError'); + assert.strictEqual(err.name, 'AbortError'); })); } diff --git a/test/js/node/test/parallel/test-child-process-fork-closed-channel-segfault.js b/test/js/node/test/parallel/test-child-process-fork-closed-channel-segfault.js index 47eb87c45fd0..73bd118ddce3 100644 --- a/test/js/node/test/parallel/test-child-process-fork-closed-channel-segfault.js +++ b/test/js/node/test/parallel/test-child-process-fork-closed-channel-segfault.js @@ -28,7 +28,7 @@ const server = net s.destroy(); }, 100); }) - .listen(0, function() { + .listen(0, common.mustCall(() => { const worker = cluster.fork(); worker.on('error', function(err) { @@ -70,9 +70,8 @@ const server = net }) ); - worker.on('online', function() { - send(function(err) { - assert.ifError(err); + worker.on('online', common.mustCall(() => { + send(common.mustSucceed(() => { send(function(err) { // Ignore errors when sending the second handle because the worker // may already have exited. @@ -83,6 +82,6 @@ const server = net throw err; } }); - }); - }); - }); + })); + })); + })); diff --git a/test/js/node/test/parallel/test-child-process-fork-ref.js b/test/js/node/test/parallel/test-child-process-fork-ref.js index bbf4432af808..ae025a72fa27 100644 --- a/test/js/node/test/parallel/test-child-process-fork-ref.js +++ b/test/js/node/test/parallel/test-child-process-fork-ref.js @@ -20,7 +20,7 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const fork = require('child_process').fork; @@ -52,8 +52,8 @@ if (process.argv[2] === 'child') { stdout += chunk; }); - child.once('exit', function() { + child.once('exit', common.mustCall(() => { assert.deepStrictEqual(ipc, ['1', '2']); assert.strictEqual(stdout, '3'); - }); + })); } diff --git a/test/js/node/test/parallel/test-child-process-fork.js b/test/js/node/test/parallel/test-child-process-fork.js index ee9dd3fc9f47..3146c4fea182 100644 --- a/test/js/node/test/parallel/test-child-process-fork.js +++ b/test/js/node/test/parallel/test-child-process-fork.js @@ -30,10 +30,10 @@ const n = fork(fixtures.path('child-process-spawn-node.js'), args); assert.deepStrictEqual(args, ['foo', 'bar']); -n.on('message', (m) => { +n.on('message', common.mustCall((m) => { debug('PARENT got message:', m); assert.ok(m.foo); -}); +})); // https://github.com/joyent/node/issues/2355 - JSON.stringify(undefined) // returns "undefined" but JSON.parse() cannot parse that... diff --git a/test/js/node/test/parallel/test-child-process-reject-null-bytes.js b/test/js/node/test/parallel/test-child-process-reject-null-bytes.js index b5239cdddcdd..3b3a25d961a9 100644 --- a/test/js/node/test/parallel/test-child-process-reject-null-bytes.js +++ b/test/js/node/test/parallel/test-child-process-reject-null-bytes.js @@ -3,7 +3,7 @@ const { mustNotCall } = require('../common'); // Regression test for https://github.com/nodejs/node/issues/44768 -const { throws } = require('assert'); +const assert = require('assert'); const { exec, execFile, @@ -16,56 +16,56 @@ const { // Tests for the 'command' argument -throws(() => exec(`${process.execPath} ${__filename} AAA BBB\0XXX CCC`, mustNotCall()), { +assert.throws(() => exec(`${process.execPath} ${__filename} AAA BBB\0XXX CCC`, mustNotCall()), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => exec('BBB\0XXX AAA CCC', mustNotCall()), { +assert.throws(() => exec('BBB\0XXX AAA CCC', mustNotCall()), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => execSync(`${process.execPath} ${__filename} AAA BBB\0XXX CCC`), { +assert.throws(() => execSync(`${process.execPath} ${__filename} AAA BBB\0XXX CCC`), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => execSync('BBB\0XXX AAA CCC'), { +assert.throws(() => execSync('BBB\0XXX AAA CCC'), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); // Tests for the 'file' argument -throws(() => spawn('BBB\0XXX'), { +assert.throws(() => spawn('BBB\0XXX'), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => execFile('BBB\0XXX', mustNotCall()), { +assert.throws(() => execFile('BBB\0XXX', mustNotCall()), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => execFileSync('BBB\0XXX'), { +assert.throws(() => execFileSync('BBB\0XXX'), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => spawn('BBB\0XXX'), { +assert.throws(() => spawn('BBB\0XXX'), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => spawnSync('BBB\0XXX'), { +assert.throws(() => spawnSync('BBB\0XXX'), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); // Tests for the 'modulePath' argument -throws(() => fork('BBB\0XXX'), { +assert.throws(() => fork('BBB\0XXX'), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); @@ -75,123 +75,123 @@ throws(() => fork('BBB\0XXX'), { // Not testing exec() and execSync() because these accept 'args' as a part of // 'command' as space-separated arguments. -throws(() => execFile(process.execPath, [__filename, 'AAA', 'BBB\0XXX', 'CCC'], mustNotCall()), { +assert.throws(() => execFile(process.execPath, [__filename, 'AAA', 'BBB\0XXX', 'CCC'], mustNotCall()), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => execFileSync(process.execPath, [__filename, 'AAA', 'BBB\0XXX', 'CCC']), { +assert.throws(() => execFileSync(process.execPath, [__filename, 'AAA', 'BBB\0XXX', 'CCC']), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => fork(__filename, ['AAA', 'BBB\0XXX', 'CCC']), { +assert.throws(() => fork(__filename, ['AAA', 'BBB\0XXX', 'CCC']), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => spawn(process.execPath, [__filename, 'AAA', 'BBB\0XXX', 'CCC']), { +assert.throws(() => spawn(process.execPath, [__filename, 'AAA', 'BBB\0XXX', 'CCC']), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => spawnSync(process.execPath, [__filename, 'AAA', 'BBB\0XXX', 'CCC']), { +assert.throws(() => spawnSync(process.execPath, [__filename, 'AAA', 'BBB\0XXX', 'CCC']), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); // Tests for the 'options.cwd' argument -throws(() => exec(process.execPath, { cwd: 'BBB\0XXX' }, mustNotCall()), { +assert.throws(() => exec(process.execPath, { cwd: 'BBB\0XXX' }, mustNotCall()), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => execFile(process.execPath, { cwd: 'BBB\0XXX' }, mustNotCall()), { +assert.throws(() => execFile(process.execPath, { cwd: 'BBB\0XXX' }, mustNotCall()), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => execFileSync(process.execPath, { cwd: 'BBB\0XXX' }), { +assert.throws(() => execFileSync(process.execPath, { cwd: 'BBB\0XXX' }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => execSync(process.execPath, { cwd: 'BBB\0XXX' }), { +assert.throws(() => execSync(process.execPath, { cwd: 'BBB\0XXX' }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => fork(__filename, { cwd: 'BBB\0XXX' }), { +assert.throws(() => fork(__filename, { cwd: 'BBB\0XXX' }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => spawn(process.execPath, { cwd: 'BBB\0XXX' }), { +assert.throws(() => spawn(process.execPath, { cwd: 'BBB\0XXX' }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => spawnSync(process.execPath, { cwd: 'BBB\0XXX' }), { +assert.throws(() => spawnSync(process.execPath, { cwd: 'BBB\0XXX' }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); // Tests for the 'options.argv0' argument -throws(() => exec(process.execPath, { argv0: 'BBB\0XXX' }, mustNotCall()), { +assert.throws(() => exec(process.execPath, { argv0: 'BBB\0XXX' }, mustNotCall()), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => execFile(process.execPath, { argv0: 'BBB\0XXX' }, mustNotCall()), { +assert.throws(() => execFile(process.execPath, { argv0: 'BBB\0XXX' }, mustNotCall()), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => execFileSync(process.execPath, { argv0: 'BBB\0XXX' }), { +assert.throws(() => execFileSync(process.execPath, { argv0: 'BBB\0XXX' }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => execSync(process.execPath, { argv0: 'BBB\0XXX' }), { +assert.throws(() => execSync(process.execPath, { argv0: 'BBB\0XXX' }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => fork(__filename, { argv0: 'BBB\0XXX' }), { +assert.throws(() => fork(__filename, { argv0: 'BBB\0XXX' }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => spawn(process.execPath, { argv0: 'BBB\0XXX' }), { +assert.throws(() => spawn(process.execPath, { argv0: 'BBB\0XXX' }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => spawnSync(process.execPath, { argv0: 'BBB\0XXX' }), { +assert.throws(() => spawnSync(process.execPath, { argv0: 'BBB\0XXX' }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); // Tests for the 'options.shell' argument -throws(() => exec(process.execPath, { shell: 'BBB\0XXX' }, mustNotCall()), { +assert.throws(() => exec(process.execPath, { shell: 'BBB\0XXX' }, mustNotCall()), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => execFile(process.execPath, { shell: 'BBB\0XXX' }, mustNotCall()), { +assert.throws(() => execFile(process.execPath, { shell: 'BBB\0XXX' }, mustNotCall()), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => execFileSync(process.execPath, { shell: 'BBB\0XXX' }), { +assert.throws(() => execFileSync(process.execPath, { shell: 'BBB\0XXX' }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => execSync(process.execPath, { shell: 'BBB\0XXX' }), { +assert.throws(() => execSync(process.execPath, { shell: 'BBB\0XXX' }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); @@ -199,96 +199,96 @@ throws(() => execSync(process.execPath, { shell: 'BBB\0XXX' }), { // Not testing fork() because it doesn't accept the shell option (internally it // explicitly sets shell to false). -throws(() => spawn(process.execPath, { shell: 'BBB\0XXX' }), { +assert.throws(() => spawn(process.execPath, { shell: 'BBB\0XXX' }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => spawnSync(process.execPath, { shell: 'BBB\0XXX' }), { +assert.throws(() => spawnSync(process.execPath, { shell: 'BBB\0XXX' }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); // Tests for the 'options.env' argument -throws(() => exec(process.execPath, { env: { 'AAA': 'BBB\0XXX' } }, mustNotCall()), { +assert.throws(() => exec(process.execPath, { env: { 'AAA': 'BBB\0XXX' } }, mustNotCall()), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => exec(process.execPath, { env: { 'BBB\0XXX': 'AAA' } }, mustNotCall()), { +assert.throws(() => exec(process.execPath, { env: { 'BBB\0XXX': 'AAA' } }, mustNotCall()), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => execFile(process.execPath, { env: { 'AAA': 'BBB\0XXX' } }, mustNotCall()), { +assert.throws(() => execFile(process.execPath, { env: { 'AAA': 'BBB\0XXX' } }, mustNotCall()), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => execFile(process.execPath, { env: { 'BBB\0XXX': 'AAA' } }, mustNotCall()), { +assert.throws(() => execFile(process.execPath, { env: { 'BBB\0XXX': 'AAA' } }, mustNotCall()), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => execFileSync(process.execPath, { env: { 'AAA': 'BBB\0XXX' } }), { +assert.throws(() => execFileSync(process.execPath, { env: { 'AAA': 'BBB\0XXX' } }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => execFileSync(process.execPath, { env: { 'BBB\0XXX': 'AAA' } }), { +assert.throws(() => execFileSync(process.execPath, { env: { 'BBB\0XXX': 'AAA' } }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => execSync(process.execPath, { env: { 'AAA': 'BBB\0XXX' } }), { +assert.throws(() => execSync(process.execPath, { env: { 'AAA': 'BBB\0XXX' } }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => execSync(process.execPath, { env: { 'BBB\0XXX': 'AAA' } }), { +assert.throws(() => execSync(process.execPath, { env: { 'BBB\0XXX': 'AAA' } }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => fork(__filename, { env: { 'AAA': 'BBB\0XXX' } }), { +assert.throws(() => fork(__filename, { env: { 'AAA': 'BBB\0XXX' } }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => fork(__filename, { env: { 'BBB\0XXX': 'AAA' } }), { +assert.throws(() => fork(__filename, { env: { 'BBB\0XXX': 'AAA' } }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => spawn(process.execPath, { env: { 'AAA': 'BBB\0XXX' } }), { +assert.throws(() => spawn(process.execPath, { env: { 'AAA': 'BBB\0XXX' } }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => spawn(process.execPath, { env: { 'BBB\0XXX': 'AAA' } }), { +assert.throws(() => spawn(process.execPath, { env: { 'BBB\0XXX': 'AAA' } }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => spawnSync(process.execPath, { env: { 'AAA': 'BBB\0XXX' } }), { +assert.throws(() => spawnSync(process.execPath, { env: { 'AAA': 'BBB\0XXX' } }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); -throws(() => spawnSync(process.execPath, { env: { 'BBB\0XXX': 'AAA' } }), { +assert.throws(() => spawnSync(process.execPath, { env: { 'BBB\0XXX': 'AAA' } }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); // Tests for the 'options.execPath' argument -throws(() => fork(__filename, { execPath: 'BBB\0XXX' }), { +assert.throws(() => fork(__filename, { execPath: 'BBB\0XXX' }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); // Tests for the 'options.execArgv' argument -throws(() => fork(__filename, { execArgv: ['AAA', 'BBB\0XXX', 'CCC'] }), { +assert.throws(() => fork(__filename, { execArgv: ['AAA', 'BBB\0XXX', 'CCC'] }), { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError', }); diff --git a/test/js/node/test/parallel/test-child-process-silent.js b/test/js/node/test/parallel/test-child-process-silent.js index 892c4527c9e2..3c0acf97555d 100644 --- a/test/js/node/test/parallel/test-child-process-silent.js +++ b/test/js/node/test/parallel/test-child-process-silent.js @@ -20,7 +20,7 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const childProcess = require('child_process'); @@ -44,9 +44,7 @@ if (process.argv[2] === 'pipe') { // Allow child process to self terminate child.disconnect(); - child.on('exit', function() { - process.exit(0); - }); + child.on('exit', common.mustCall()); } else { // Testcase | start primary && child IPC test diff --git a/test/js/node/test/parallel/test-child-process-spawnsync-args.js b/test/js/node/test/parallel/test-child-process-spawnsync-args.js index 4e65b22f6e45..997852cae118 100644 --- a/test/js/node/test/parallel/test-child-process-spawnsync-args.js +++ b/test/js/node/test/parallel/test-child-process-spawnsync-args.js @@ -32,7 +32,7 @@ const testCases = [ const expectedResult = tmpdir.path.trim().toLowerCase(); -const results = testCases.map((testCase) => { +const results = testCases.map(common.mustCallAtLeast((testCase) => { const { stdout, stderr, error } = spawnSync( command, testCase, @@ -43,6 +43,6 @@ const results = testCases.map((testCase) => { assert.deepStrictEqual(stderr, Buffer.alloc(0)); return stdout.toString().trim().toLowerCase(); -}); +})); assert.deepStrictEqual([...new Set(results)], [expectedResult]); diff --git a/test/js/node/test/parallel/test-child-process-spawnsync-input.js b/test/js/node/test/parallel/test-child-process-spawnsync-input.js index 62ae476ae17c..f0c3d3d78978 100644 --- a/test/js/node/test/parallel/test-child-process-spawnsync-input.js +++ b/test/js/node/test/parallel/test-child-process-spawnsync-input.js @@ -65,7 +65,6 @@ if (process.argv.includes('spawnchild')) { checkSpawnSyncRet(ret); break; } - process.exit(0); return; } diff --git a/test/js/node/test/parallel/test-child-process-spawnsync-timeout.js b/test/js/node/test/parallel/test-child-process-spawnsync-timeout.js index 36f2555ac844..426ac05a4349 100644 --- a/test/js/node/test/parallel/test-child-process-spawnsync-timeout.js +++ b/test/js/node/test/parallel/test-child-process-spawnsync-timeout.js @@ -39,7 +39,6 @@ if (common.isWindows) { switch (process.argv[2]) { case 'child': - console.log('child started'); setTimeout(() => { debug('child fired'); process.exit(1); diff --git a/test/js/node/test/parallel/test-child-process-stdio-inherit.js b/test/js/node/test/parallel/test-child-process-stdio-inherit.js index 034a0770168b..73a5bc802c76 100644 --- a/test/js/node/test/parallel/test-child-process-stdio-inherit.js +++ b/test/js/node/test/parallel/test-child-process-stdio-inherit.js @@ -20,7 +20,7 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const spawn = require('child_process').spawn; @@ -42,12 +42,12 @@ function grandparent() { child.stdin.end(input); - child.on('close', function(code, signal) { + child.on('close', common.mustCall((code, signal) => { assert.strictEqual(code, 0); assert.strictEqual(signal, null); // 'cat' on windows adds a \r\n at the end. assert.strictEqual(output.trim(), input.trim()); - }); + })); } function parent() { diff --git a/test/js/node/test/parallel/test-child-process-stdout-flush-exit.js b/test/js/node/test/parallel/test-child-process-stdout-flush-exit.js index 90f746c39ef6..4c5de7d9a2b4 100644 --- a/test/js/node/test/parallel/test-child-process-stdout-flush-exit.js +++ b/test/js/node/test/parallel/test-child-process-stdout-flush-exit.js @@ -36,7 +36,6 @@ if (process.argv[2] === 'child') { console.log('filler'); } console.log('goodbye'); - process.exit(0); } else { // parent process const spawn = require('child_process').spawn; diff --git a/test/js/node/test/parallel/test-crypto-certificate.js b/test/js/node/test/parallel/test-crypto-certificate.js index 6b02d07f3ce0..28d20ba61c75 100644 --- a/test/js/node/test/parallel/test-crypto-certificate.js +++ b/test/js/node/test/parallel/test-crypto-certificate.js @@ -103,22 +103,6 @@ function checkMethods(certificate) { checkMethods(Certificate); } -{ - const spkacText = spkacValid.toString('utf8').trimEnd(); - const padded = Buffer.alloc(Buffer.byteLength(spkacText) + 1); - padded.write(spkacText); - const zeroLengthView = padded.subarray(0, 0); - assert.strictEqual(Certificate.verifySpkac(zeroLengthView), false); - assert.strictEqual(Certificate.exportPublicKey(zeroLengthView), ''); - assert.strictEqual(Certificate.exportChallenge(zeroLengthView), ''); - - for (const input of [Buffer.alloc(0), Buffer.from(' \n\r\t'), '', ' \n\r\t']) { - assert.strictEqual(Certificate.verifySpkac(Buffer.from(input)), false); - assert.strictEqual(Certificate.exportPublicKey(input), ''); - assert.strictEqual(Certificate.exportChallenge(input), ''); - } -} - function stripLineEndings(obj) { return obj.replace(/\n/g, ''); } diff --git a/test/js/node/test/parallel/test-crypto-keyobject-brand-check.js b/test/js/node/test/parallel/test-crypto-keyobject-brand-check.js index fffd6e4a8885..ac0cf1b65f70 100644 --- a/test/js/node/test/parallel/test-crypto-keyobject-brand-check.js +++ b/test/js/node/test/parallel/test-crypto-keyobject-brand-check.js @@ -18,16 +18,6 @@ const { const { types: { isKeyObject } } = require('node:util'); const invalidThis = { code: 'ERR_INVALID_THIS', name: 'TypeError' }; -// A non-KeyObject receiver names "KeyObject"; a KeyObject of the wrong kind names the -// specific subclass the getter lives on. -const notKeyObject = { - ...invalidThis, - message: 'Value of "this" must be of type KeyObject', -}; -const wrongKind = (expected) => ({ - ...invalidThis, - message: `Value of "this" must be of type ${expected}`, -}); function getter(proto, name) { return Object.getOwnPropertyDescriptor(proto, name).get; @@ -62,25 +52,22 @@ function getter(proto, name) { for (const value of [{}, { __proto__: null }, 1, null, undefined, Buffer.alloc(1), function() {}]) { - assert.throws(() => type.call(value), notKeyObject); - assert.throws(() => symmetricKeySize.call(value), notKeyObject); - assert.throws(() => asymmetricKeyType.call(value), notKeyObject); - assert.throws(() => asymmetricKeyDetails.call(value), notKeyObject); + assert.throws(() => type.call(value), invalidThis); + assert.throws(() => symmetricKeySize.call(value), invalidThis); + assert.throws(() => asymmetricKeyType.call(value), invalidThis); + assert.throws(() => asymmetricKeyDetails.call(value), invalidThis); } - assert.throws(() => symmetricKeySize.call(publicKey), - wrongKind('SecretKeyObject')); - assert.throws(() => asymmetricKeyType.call(secret), - wrongKind('AsymmetricKeyObject')); - assert.throws(() => asymmetricKeyDetails.call(secret), - wrongKind('AsymmetricKeyObject')); + assert.throws(() => symmetricKeySize.call(publicKey), invalidThis); + assert.throws(() => asymmetricKeyType.call(secret), invalidThis); + assert.throws(() => asymmetricKeyDetails.call(secret), invalidThis); const spoofed = {}; Object.setPrototypeOf(spoofed, Object.getPrototypeOf(secret)); assert.strictEqual(spoofed instanceof KeyObject, true); assert.strictEqual(isKeyObject(spoofed), false); - assert.throws(() => type.call(spoofed), notKeyObject); - assert.throws(() => symmetricKeySize.call(spoofed), notKeyObject); + assert.throws(() => type.call(spoofed), invalidThis); + assert.throws(() => symmetricKeySize.call(spoofed), invalidThis); assert.throws(() => createHmac('sha256', spoofed), { code: 'ERR_INVALID_ARG_TYPE', }); @@ -95,10 +82,10 @@ function getter(proto, name) { const buf = Buffer.alloc(16); assert.strictEqual(buf instanceof KeyObject, true); assert.strictEqual(isKeyObject(buf), false); - assert.throws(() => type.call(buf), notKeyObject); - assert.throws(() => symmetricKeySize.call(buf), notKeyObject); - assert.throws(() => asymmetricKeyType.call(buf), notKeyObject); - assert.throws(() => asymmetricKeyDetails.call(buf), notKeyObject); + assert.throws(() => type.call(buf), invalidThis); + assert.throws(() => symmetricKeySize.call(buf), invalidThis); + assert.throws(() => asymmetricKeyType.call(buf), invalidThis); + assert.throws(() => asymmetricKeyDetails.call(buf), invalidThis); } finally { if (originalHasInstance === undefined) { delete KeyObject[Symbol.hasInstance]; diff --git a/test/js/node/test/parallel/test-crypto-rsa-dsa.js b/test/js/node/test/parallel/test-crypto-rsa-dsa.js index 2c28c28c2198..35ad67302077 100644 --- a/test/js/node/test/parallel/test-crypto-rsa-dsa.js +++ b/test/js/node/test/parallel/test-crypto-rsa-dsa.js @@ -234,6 +234,8 @@ function test_rsa(padding, encryptOaepHash, decryptOaepHash) { if (padding === constants.RSA_PKCS1_PADDING) { if (!process.config.variables.node_shared_openssl) { + // TODO(richardlau) remove check and else branch after deps/openssl + // is upgraded. if (hasOpenSSL(3, 2)) { let decryptedBuffer = crypto.privateDecrypt({ key: rsaKeyPem, diff --git a/test/js/node/test/parallel/test-debug-process.js b/test/js/node/test/parallel/test-debug-process.js index 0d10a15e2eef..4eb5ad7b4d5d 100644 --- a/test/js/node/test/parallel/test-debug-process.js +++ b/test/js/node/test/parallel/test-debug-process.js @@ -16,6 +16,6 @@ cp.on('exit', common.mustCall(function() { try { process._debugProcess(cp.pid); } catch (error) { - assert.strictEqual(error.message, 'The system cannot find the file specified.'); + assert.strictEqual(error.errno, 2); } })); diff --git a/test/js/node/test/parallel/test-debugger-backtrace.js b/test/js/node/test/parallel/test-debugger-backtrace.js index f66cc11d70a9..c189cb3f5b22 100644 --- a/test/js/node/test/parallel/test-debugger-backtrace.js +++ b/test/js/node/test/parallel/test-debugger-backtrace.js @@ -13,7 +13,7 @@ const path = require('path'); { const scriptFullPath = fixtures.path('debugger', 'backtrace.js'); const script = path.relative(process.cwd(), scriptFullPath); - const cli = startCLI(['--port=0', script]); + const cli = startCLI([script]); async function runTest() { try { diff --git a/test/js/node/test/parallel/test-debugger-exec.js b/test/js/node/test/parallel/test-debugger-exec.js index 536e0128ea2a..2b6c50ab61ff 100644 --- a/test/js/node/test/parallel/test-debugger-exec.js +++ b/test/js/node/test/parallel/test-debugger-exec.js @@ -8,7 +8,7 @@ const startCLI = require('../common/debugger'); const assert = require('assert'); -const cli = startCLI(['--port=0', fixtures.path('debugger/alive.js')]); +const cli = startCLI([fixtures.path('debugger/alive.js')]); async function waitInitialBreak() { try { diff --git a/test/js/node/test/parallel/test-debugger-invalid-json.mjs b/test/js/node/test/parallel/test-debugger-invalid-json.mjs index e4754a465fcf..1c2b4b475b7e 100644 --- a/test/js/node/test/parallel/test-debugger-invalid-json.mjs +++ b/test/js/node/test/parallel/test-debugger-invalid-json.mjs @@ -17,7 +17,7 @@ const host = '127.0.0.1'; server.listen(0, mustCall(async () => { const port = server.address().port; - const cli = startCLI([`${host}:${port}`]); + const cli = startCLI([`${host}:${port}`], [], {}, { randomPort: false }); try { const code = await cli.quit(); assert.strictEqual(code, 1); @@ -35,7 +35,7 @@ const host = '127.0.0.1'; server.listen(0, host, mustCall(async () => { const port = server.address().port; - const cli = startCLI([`${host}:${port}`]); + const cli = startCLI([`${host}:${port}`], [], {}, { randomPort: false }); try { const code = await cli.quit(); assert.strictEqual(code, 1); diff --git a/test/js/node/test/parallel/test-debugger-low-level.js b/test/js/node/test/parallel/test-debugger-low-level.js index 31f67849f547..93c8e1b62559 100644 --- a/test/js/node/test/parallel/test-debugger-low-level.js +++ b/test/js/node/test/parallel/test-debugger-low-level.js @@ -9,7 +9,7 @@ const assert = require('assert'); // Debugger agent direct access. { - const cli = startCLI(['--port=0', fixtures.path('debugger/three-lines.js')]); + const cli = startCLI([fixtures.path('debugger/three-lines.js')]); const scriptPattern = /^\* (\d+): \S+debugger(?:\/|\\)three-lines\.js/m; async function testDebuggerLowLevel() { diff --git a/test/js/node/test/parallel/test-debugger-repeat-last.js b/test/js/node/test/parallel/test-debugger-repeat-last.js index 9a9b8eecdc71..5b403035dc46 100644 --- a/test/js/node/test/parallel/test-debugger-repeat-last.js +++ b/test/js/node/test/parallel/test-debugger-repeat-last.js @@ -1,10 +1,10 @@ 'use strict'; const common = require('../common'); common.skipIfInspectorDisabled(); -const path = require('../common/fixtures').path; +const fixtures = require('../common/fixtures'); const spawn = require('child_process').spawn; const assert = require('assert'); -const fixture = path('debugger-repeat-last.js'); +const fixture = fixtures.path('debugger-repeat-last.js'); const args = [ 'inspect', diff --git a/test/js/node/test/parallel/test-debugger-restart-message.js b/test/js/node/test/parallel/test-debugger-restart-message.js index e4001b47ee2d..3f19e22f550e 100644 --- a/test/js/node/test/parallel/test-debugger-restart-message.js +++ b/test/js/node/test/parallel/test-debugger-restart-message.js @@ -14,23 +14,29 @@ const startCLI = require('../common/debugger'); // Using `restart` should result in only one "Connect/For help" message. { const script = fixtures.path('debugger', 'three-lines.js'); - const cli = startCLI(['--port=0', script]); + const cli = startCLI([script]); const listeningRegExp = /Debugger listening on/g; async function onWaitForInitialBreak() { try { - await cli.waitForInitialBreak(); + await cli.waitFor(/ ok\n/); await cli.waitForPrompt(); assert.strictEqual(cli.output.match(listeningRegExp).length, 1); for (let i = 0; i < RESTARTS; i++) { - await cli.stepCommand('restart'); + // For `restart`, sync on attach/prompt instead of BREAK_MESSAGE to avoid flaky races. + // https://github.com/nodejs/node/issues/61762 + await cli.command('restart'); + await cli.waitFor(/Debugger attached\./); + await cli.waitForPrompt(); assert.strictEqual(cli.output.match(listeningRegExp).length, 1); } } finally { await cli.quit(); } + + assert.doesNotMatch(cli.stderrOutput, /MaxListenersExceededWarning/); } onWaitForInitialBreak(); diff --git a/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-callback-error.js b/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-callback-error.js index 672500e76832..0767db3b7ad5 100644 --- a/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-callback-error.js +++ b/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-callback-error.js @@ -27,10 +27,10 @@ const handlers = { channel.subscribe(handlers); -channel.traceCallback(function(cb, err) { +channel.traceCallback(common.mustCall(function(cb, err) { assert.deepStrictEqual(this, thisArg); setImmediate(cb, err); -}, 0, input, thisArg, common.mustCall((err, res) => { +}), 0, input, thisArg, common.mustCall((err, res) => { assert.strictEqual(err, expectedError); assert.strictEqual(res, undefined); }), expectedError); diff --git a/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-callback.js b/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-callback.js index d306f0f51b7c..dbe2406475ac 100644 --- a/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-callback.js +++ b/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-callback.js @@ -30,10 +30,10 @@ const handlers = { channel.subscribe(handlers); -channel.traceCallback(function(cb, err, res) { +channel.traceCallback(common.mustCall(function(cb, err, res) { assert.deepStrictEqual(this, thisArg); setImmediate(cb, err, res); -}, 0, input, thisArg, common.mustCall((err, res) => { +}), 0, input, thisArg, common.mustCall((err, res) => { assert.strictEqual(err, null); assert.deepStrictEqual(res, expectedResult); }), null, expectedResult); diff --git a/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-promise-error.js b/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-promise-error.js index f1f52d72f800..4a193b52a764 100644 --- a/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-promise-error.js +++ b/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-promise-error.js @@ -27,12 +27,10 @@ const handlers = { channel.subscribe(handlers); -channel.tracePromise(function(value) { - assert.deepStrictEqual(this, thisArg); - return Promise.reject(value); -}, input, thisArg, expectedError).then( - common.mustNotCall(), - common.mustCall((value) => { - assert.deepStrictEqual(value, expectedError); - }) -); +assert.rejects( + channel.tracePromise(common.mustCall(function(value) { + assert.deepStrictEqual(this, thisArg); + return Promise.reject(value); + }), input, thisArg, expectedError), + expectedError, +).then(common.mustCall()); diff --git a/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-promise.js b/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-promise.js index 20892ca40f59..1ac1a5649628 100644 --- a/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-promise.js +++ b/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-promise.js @@ -30,12 +30,11 @@ const handlers = { channel.subscribe(handlers); -channel.tracePromise(function(value) { +channel.tracePromise(common.mustCall(function(value) { assert.deepStrictEqual(this, thisArg); return Promise.resolve(value); -}, input, thisArg, expectedResult).then( +}), input, thisArg, expectedResult).then( common.mustCall((value) => { assert.deepStrictEqual(value, expectedResult); }), - common.mustNotCall() ); diff --git a/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-sync-error.js b/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-sync-error.js index 0965bf3fb495..b7b5084bae61 100644 --- a/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-sync-error.js +++ b/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-sync-error.js @@ -27,11 +27,11 @@ const handlers = { channel.subscribe(handlers); try { - channel.traceSync(function(err) { + channel.traceSync(common.mustCall(function(err) { assert.deepStrictEqual(this, thisArg); assert.strictEqual(err, expectedError); throw err; - }, input, thisArg, expectedError); + }), input, thisArg, expectedError); throw new Error('It should not reach this error'); } catch (error) { diff --git a/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-sync.js b/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-sync.js index b28b47256b75..1cc5feb6d0dc 100644 --- a/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-sync.js +++ b/test/js/node/test/parallel/test-diagnostics-channel-tracing-channel-sync.js @@ -29,18 +29,18 @@ const handlers = { assert.strictEqual(channel.start.hasSubscribers, false); channel.subscribe(handlers); assert.strictEqual(channel.start.hasSubscribers, true); -const result1 = channel.traceSync(function(arg1) { +const result1 = channel.traceSync(common.mustCall(function(arg1) { assert.strictEqual(arg1, arg); assert.strictEqual(this, thisArg); return expectedResult; -}, input, thisArg, arg); +}), input, thisArg, arg); assert.strictEqual(result1, expectedResult); channel.unsubscribe(handlers); assert.strictEqual(channel.start.hasSubscribers, false); -const result2 = channel.traceSync(function(arg1) { +const result2 = channel.traceSync(common.mustCall(function(arg1) { assert.strictEqual(arg1, arg); assert.strictEqual(this, thisArg); return expectedResult; -}, input, thisArg, arg); +}), input, thisArg, arg); assert.strictEqual(result2, expectedResult); diff --git a/test/js/node/test/parallel/test-dns-setservers-type-check.js b/test/js/node/test/parallel/test-dns-setservers-type-check.js index 7a19dc5eb067..007cae4f95d6 100644 --- a/test/js/node/test/parallel/test-dns-setservers-type-check.js +++ b/test/js/node/test/parallel/test-dns-setservers-type-check.js @@ -20,7 +20,8 @@ const promiseResolver = new dns.promises.Resolver(); const errObj = { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', - message: /^The "servers" argument must be an instance of Array\./ + message: 'The "servers" argument must be an instance of Array.' + + common.invalidArgTypeHelper(val) }; assert.throws( () => { @@ -59,7 +60,8 @@ const promiseResolver = new dns.promises.Resolver(); const errObj = { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', - message: /^The "servers\[0\]" argument must be of type string\./ + message: 'The "servers[0]" argument must be of type string.' + + common.invalidArgTypeHelper(val[0]) }; assert.throws( () => { @@ -108,7 +110,8 @@ const promiseResolver = new dns.promises.Resolver(); const errObj = { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', - message: /^The "servers\[0\]" argument must be of type string\./ + message: 'The "servers[0]" argument must be of type string.' + + common.invalidArgTypeHelper(val[0]) }; assert.throws(() => { setServers(val); diff --git a/test/js/node/test/parallel/test-domain-nested-throw.js b/test/js/node/test/parallel/test-domain-nested-throw.js index ec016ada7285..ee16d86f107e 100644 --- a/test/js/node/test/parallel/test-domain-nested-throw.js +++ b/test/js/node/test/parallel/test-domain-nested-throw.js @@ -20,7 +20,7 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const domain = require('domain'); @@ -35,10 +35,9 @@ function parent() { const spawn = require('child_process').spawn; const opt = { stdio: 'inherit' }; const child = spawn(node, [__filename, 'child'], opt); - child.on('exit', function(c) { + child.on('exit', common.mustCall((c) => { assert(!c); - console.log('ok'); - }); + })); } let gotDomain1Error = false; diff --git a/test/js/node/test/parallel/test-domexception-cause.js b/test/js/node/test/parallel/test-domexception-cause.js index 179ef6d212ae..c5a9f61c234b 100644 --- a/test/js/node/test/parallel/test-domexception-cause.js +++ b/test/js/node/test/parallel/test-domexception-cause.js @@ -1,33 +1,33 @@ 'use strict'; require('../common'); -const { strictEqual, deepStrictEqual } = require('assert'); +const assert = require('assert'); { const domException = new DOMException('no cause', 'abc'); - strictEqual(domException.name, 'abc'); - strictEqual('cause' in domException, false); - strictEqual(domException.cause, undefined); + assert.strictEqual(domException.name, 'abc'); + assert.strictEqual('cause' in domException, false); + assert.strictEqual(domException.cause, undefined); } { const domException = new DOMException('with undefined cause', { name: 'abc', cause: undefined }); - strictEqual(domException.name, 'abc'); - strictEqual('cause' in domException, true); - strictEqual(domException.cause, undefined); + assert.strictEqual(domException.name, 'abc'); + assert.strictEqual('cause' in domException, true); + assert.strictEqual(domException.cause, undefined); } { const domException = new DOMException('with string cause', { name: 'abc', cause: 'foo' }); - strictEqual(domException.name, 'abc'); - strictEqual('cause' in domException, true); - strictEqual(domException.cause, 'foo'); + assert.strictEqual(domException.name, 'abc'); + assert.strictEqual('cause' in domException, true); + assert.strictEqual(domException.cause, 'foo'); } { const object = { reason: 'foo' }; const domException = new DOMException('with object cause', { name: 'abc', cause: object }); - strictEqual(domException.name, 'abc'); - strictEqual('cause' in domException, true); - deepStrictEqual(domException.cause, object); + assert.strictEqual(domException.name, 'abc'); + assert.strictEqual('cause' in domException, true); + assert.deepStrictEqual(domException.cause, object); } diff --git a/test/js/node/test/parallel/test-event-emitter-add-listeners.js b/test/js/node/test/parallel/test-event-emitter-add-listeners.js index f42d1f248784..5d17fd0db085 100644 --- a/test/js/node/test/parallel/test-event-emitter-add-listeners.js +++ b/test/js/node/test/parallel/test-event-emitter-add-listeners.js @@ -46,11 +46,11 @@ const EventEmitter = require('events'); assert.strictEqual(b, 'b'); }); - ee.once('newListener', function(name, listener) { + ee.once('newListener', common.mustCall(function(name, listener) { assert.strictEqual(name, 'hello'); assert.strictEqual(listener, hello); assert.deepStrictEqual(this.listeners('hello'), []); - }); + })); ee.on('hello', hello); ee.once('foo', assert.fail); @@ -72,13 +72,13 @@ const EventEmitter = require('events'); const listen2 = () => {}; const ee = new EventEmitter(); - ee.once('newListener', function() { + ee.once('newListener', common.mustCall(() => { assert.deepStrictEqual(ee.listeners('hello'), []); - ee.once('newListener', function() { + ee.once('newListener', common.mustCall(() => { assert.deepStrictEqual(ee.listeners('hello'), []); - }); + })); ee.on('hello', listen2); - }); + })); ee.on('hello', listen1); // The order of listeners on an event is not always the order in which the // listeners were added. diff --git a/test/js/node/test/parallel/test-event-emitter-method-names.js b/test/js/node/test/parallel/test-event-emitter-method-names.js index 684024d02762..8ee44f41d588 100644 --- a/test/js/node/test/parallel/test-event-emitter-method-names.js +++ b/test/js/node/test/parallel/test-event-emitter-method-names.js @@ -28,8 +28,8 @@ const E = events.EventEmitter.prototype; assert.strictEqual(E.constructor.name, 'EventEmitter'); assert.strictEqual(E.on, E.addListener); // Same method. assert.strictEqual(E.off, E.removeListener); // Same method. -Object.getOwnPropertyNames(E).forEach(function(name) { +for (const name of Object.getOwnPropertyNames(E)) { if (name === 'constructor' || name === 'on' || name === 'off') return; if (typeof E[name] !== 'function') return; assert.strictEqual(E[name].name, name); -}); +} diff --git a/test/js/node/test/parallel/test-event-emitter-remove-all-listeners.js b/test/js/node/test/parallel/test-event-emitter-remove-all-listeners.js index c62183fd08c2..bca8f3eb1650 100644 --- a/test/js/node/test/parallel/test-event-emitter-remove-all-listeners.js +++ b/test/js/node/test/parallel/test-event-emitter-remove-all-listeners.js @@ -87,9 +87,9 @@ function expect(expected) { { const ee = new events.EventEmitter(); let expectLength = 2; - ee.on('removeListener', function(name, noop) { + ee.on('removeListener', common.mustCallAtLeast(function(name, noop) { assert.strictEqual(expectLength--, this.listeners('baz').length); - }); + })); ee.on('baz', common.mustNotCall()); ee.on('baz', common.mustNotCall()); ee.on('baz', common.mustNotCall()); diff --git a/test/js/node/test/parallel/test-event-emitter-remove-listeners.js b/test/js/node/test/parallel/test-event-emitter-remove-listeners.js index e9e4a74a5b63..7b94d31f45d2 100644 --- a/test/js/node/test/parallel/test-event-emitter-remove-listeners.js +++ b/test/js/node/test/parallel/test-event-emitter-remove-listeners.js @@ -144,19 +144,6 @@ function listener2() {} assert.deepStrictEqual(ee, ee.removeListener('foo', () => {})); } -{ - const ee = new EventEmitter(); - ee.on('persistent', listener1); - - for (let i = 0; i < 100; i++) { - const eventName = `event-${i}`; - ee.on(eventName, listener2); - ee.removeListener(eventName, listener2); - } - - assert.deepStrictEqual(Reflect.ownKeys(ee._events), ['persistent']); -} - { const ee = new EventEmitter(); const listener = () => {}; diff --git a/test/js/node/test/parallel/test-events-add-abort-listener.mjs b/test/js/node/test/parallel/test-events-add-abort-listener.mjs index f8de1e2e42a1..69b6a054e395 100644 --- a/test/js/node/test/parallel/test-events-add-abort-listener.mjs +++ b/test/js/node/test/parallel/test-events-add-abort-listener.mjs @@ -1,7 +1,7 @@ -import * as assert from 'node:assert'; +import * as common from '../common/index.mjs'; import * as events from 'node:events'; +import * as assert from 'node:assert'; import { describe, it } from 'node:test'; -import * as common from '../common/index.mjs'; describe('events.addAbortListener', () => { it('should throw if signal not provided', () => { @@ -52,4 +52,4 @@ describe('events.addAbortListener', () => { disposable[Symbol.dispose](); controller.abort(); }); -}); \ No newline at end of file +}); diff --git a/test/js/node/test/parallel/test-events-once.js b/test/js/node/test/parallel/test-events-once.js index d5eadeaca0e9..2a3d3c97ae20 100644 --- a/test/js/node/test/parallel/test-events-once.js +++ b/test/js/node/test/parallel/test-events-once.js @@ -1,14 +1,9 @@ 'use strict'; -// Flags: --expose-internals --no-warnings +// Flags: --no-warnings const common = require('../common'); const { once, EventEmitter, listenerCount } = require('events'); -const { - deepStrictEqual, - fail, - rejects, - strictEqual, -} = require('assert'); +const assert = require('assert'); async function onceAnEvent() { const ee = new EventEmitter(); @@ -18,16 +13,16 @@ async function onceAnEvent() { }); const [value] = await once(ee, 'myevent'); - strictEqual(value, 42); - strictEqual(ee.listenerCount('error'), 0); - strictEqual(ee.listenerCount('myevent'), 0); + assert.strictEqual(value, 42); + assert.strictEqual(ee.listenerCount('error'), 0); + assert.strictEqual(ee.listenerCount('myevent'), 0); } async function onceAnEventWithInvalidOptions() { const ee = new EventEmitter(); await Promise.all([1, 'hi', null, false, () => {}, Symbol(), 1n].map((options) => { - return rejects(once(ee, 'myevent', options), { + return assert.rejects(once(ee, 'myevent', options), { code: 'ERR_INVALID_ARG_TYPE', }); })); @@ -41,7 +36,7 @@ async function onceAnEventWithTwoArgs() { }); const value = await once(ee, 'myevent'); - deepStrictEqual(value, [42, 24]); + assert.deepStrictEqual(value, [42, 24]); } async function catchesErrors() { @@ -58,9 +53,9 @@ async function catchesErrors() { } catch (_e) { err = _e; } - strictEqual(err, expected); - strictEqual(ee.listenerCount('error'), 0); - strictEqual(ee.listenerCount('myevent'), 0); + assert.strictEqual(err, expected); + assert.strictEqual(ee.listenerCount('error'), 0); + assert.strictEqual(ee.listenerCount('myevent'), 0); } async function catchesErrorsWithAbortSignal() { @@ -76,17 +71,17 @@ async function catchesErrorsWithAbortSignal() { try { const promise = once(ee, 'myevent', { signal }); - strictEqual(ee.listenerCount('error'), 1); - strictEqual(listenerCount(signal, "abort"), 1); + assert.strictEqual(ee.listenerCount('error'), 1); + assert.strictEqual(listenerCount(signal, 'abort'), 1); await promise; } catch (e) { err = e; } - strictEqual(err, expected); - strictEqual(ee.listenerCount('error'), 0); - strictEqual(ee.listenerCount('myevent'), 0); - strictEqual(listenerCount(signal, "abort"), 0); + assert.strictEqual(err, expected); + assert.strictEqual(ee.listenerCount('error'), 0); + assert.strictEqual(ee.listenerCount('myevent'), 0); + assert.strictEqual(listenerCount(signal, 'abort'), 0); } async function stopListeningAfterCatchingError() { @@ -104,10 +99,9 @@ async function stopListeningAfterCatchingError() { } catch (_e) { err = _e; } - process.removeAllListeners('multipleResolves'); - strictEqual(err, expected); - strictEqual(ee.listenerCount('error'), 0); - strictEqual(ee.listenerCount('myevent'), 0); + assert.strictEqual(err, expected); + assert.strictEqual(ee.listenerCount('error'), 0); + assert.strictEqual(ee.listenerCount('myevent'), 0); } async function onceError() { @@ -119,11 +113,11 @@ async function onceError() { }); const promise = once(ee, 'error'); - strictEqual(ee.listenerCount('error'), 1); + assert.strictEqual(ee.listenerCount('error'), 1); const [ err ] = await promise; - strictEqual(err, expected); - strictEqual(ee.listenerCount('error'), 0); - strictEqual(ee.listenerCount('myevent'), 0); + assert.strictEqual(err, expected); + assert.strictEqual(ee.listenerCount('error'), 0); + assert.strictEqual(ee.listenerCount('myevent'), 0); } async function onceWithEventTarget() { @@ -133,7 +127,7 @@ async function onceWithEventTarget() { et.dispatchEvent(event); }); const [ value ] = await once(et, 'myevent'); - strictEqual(value, event); + assert.strictEqual(value, event); } async function onceWithEventTargetError() { @@ -144,20 +138,20 @@ async function onceWithEventTargetError() { }); const [ err ] = await once(et, 'error'); - strictEqual(err, error); + assert.strictEqual(err, error); } async function onceWithInvalidEventEmmiter() { const ac = new AbortController(); - return rejects(once(ac, 'myevent'), { + return assert.rejects(once(ac, 'myevent'), { code: 'ERR_INVALID_ARG_TYPE', }); } async function prioritizesEventEmitter() { const ee = new EventEmitter(); - ee.addEventListener = fail; - ee.removeAllListeners = fail; + ee.addEventListener = assert.fail; + ee.removeAllListeners = assert.fail; process.nextTick(() => ee.emit('foo')); await once(ee, 'foo'); } @@ -168,12 +162,12 @@ async function abortSignalBefore() { const abortedSignal = AbortSignal.abort(); await Promise.all([1, {}, 'hi', null, false].map((signal) => { - return rejects(once(ee, 'foo', { signal }), { + return assert.rejects(once(ee, 'foo', { signal }), { code: 'ERR_INVALID_ARG_TYPE', }); })); - return rejects(once(ee, 'foo', { signal: abortedSignal }), { + return assert.rejects(once(ee, 'foo', { signal: abortedSignal }), { name: 'AbortError', }); } @@ -182,7 +176,7 @@ async function abortSignalAfter() { const ee = new EventEmitter(); const ac = new AbortController(); ee.on('error', common.mustNotCall()); - const r = rejects(once(ee, 'foo', { signal: ac.signal }), { + const r = assert.rejects(once(ee, 'foo', { signal: ac.signal }), { name: 'AbortError', }); process.nextTick(() => ac.abort()); @@ -197,9 +191,9 @@ async function abortSignalAfterEvent() { ac.abort(); }); const promise = once(ee, 'foo', { signal: ac.signal }); - strictEqual(listenerCount(ac.signal, "abort"), 1); + assert.strictEqual(listenerCount(ac.signal, 'abort'), 1); await promise; - strictEqual(listenerCount(ac.signal, "abort"), 0); + assert.strictEqual(listenerCount(ac.signal, 'abort'), 0); } async function abortSignalRemoveListener() { @@ -210,8 +204,8 @@ async function abortSignalRemoveListener() { process.nextTick(() => ac.abort()); await once(ee, 'test', { signal: ac.signal }); } catch { - strictEqual(ee.listeners('test').length, 0); - strictEqual(ee.listeners('error').length, 0); + assert.strictEqual(ee.listeners('test').length, 0); + assert.strictEqual(ee.listeners('error').length, 0); } } @@ -220,33 +214,32 @@ async function eventTargetAbortSignalBefore() { const abortedSignal = AbortSignal.abort(); await Promise.all([1, {}, 'hi', null, false].map((signal) => { - return rejects(once(et, 'foo', { signal }), { + return assert.rejects(once(et, 'foo', { signal }), { code: 'ERR_INVALID_ARG_TYPE', }); })); - return rejects(once(et, 'foo', { signal: abortedSignal }), { + return assert.rejects(once(et, 'foo', { signal: abortedSignal }), { name: 'AbortError', }); } -// TODO: unskip -// async function eventTargetAbortSignalBeforeEvenWhenSignalPropagationStopped() { -// const et = new EventTarget(); -// const ac = new AbortController(); -// const { signal } = ac; -// signal.addEventListener('abort', (e) => e.stopImmediatePropagation(), { once: true }); - -// process.nextTick(() => ac.abort()); -// return rejects(once(et, 'foo', { signal }), { -// name: 'AbortError', -// }); -// } +async function eventTargetAbortSignalBeforeEvenWhenSignalPropagationStopped() { + const et = new EventTarget(); + const ac = new AbortController(); + const { signal } = ac; + signal.addEventListener('abort', (e) => e.stopImmediatePropagation(), { once: true }); + + process.nextTick(() => ac.abort()); + return assert.rejects(once(et, 'foo', { signal }), { + name: 'AbortError', + }); +} async function eventTargetAbortSignalAfter() { const et = new EventTarget(); const ac = new AbortController(); - const r = rejects(once(et, 'foo', { signal: ac.signal }), { + const r = assert.rejects(once(et, 'foo', { signal: ac.signal }), { name: 'AbortError', }); process.nextTick(() => ac.abort()); @@ -280,7 +273,7 @@ Promise.all([ abortSignalAfterEvent(), abortSignalRemoveListener(), eventTargetAbortSignalBefore(), - // eventTargetAbortSignalBeforeEvenWhenSignalPropagationStopped(), + eventTargetAbortSignalBeforeEvenWhenSignalPropagationStopped(), eventTargetAbortSignalAfter(), eventTargetAbortSignalAfterEvent(), ]).then(common.mustCall()); diff --git a/test/js/node/test/parallel/test-events-static-geteventlisteners.js b/test/js/node/test/parallel/test-events-static-geteventlisteners.js index 35b4e34325a8..2f450f076457 100644 --- a/test/js/node/test/parallel/test-events-static-geteventlisteners.js +++ b/test/js/node/test/parallel/test-events-static-geteventlisteners.js @@ -1,11 +1,9 @@ 'use strict'; // Flags: --expose-internals --no-warnings const common = require('../common'); +const { kWeakHandler } = require('internal/event_target'); -const { - deepStrictEqual, - throws, -} = require('assert'); +const assert = require('assert'); const { getEventListeners, EventEmitter } = require('events'); @@ -18,9 +16,9 @@ const { getEventListeners, EventEmitter } = require('events'); emitter.on('foo', fn2); emitter.on('baz', fn1); emitter.on('baz', fn1); - deepStrictEqual(getEventListeners(emitter, 'foo'), [fn1, fn2]); - deepStrictEqual(getEventListeners(emitter, 'bar'), []); - deepStrictEqual(getEventListeners(emitter, 'baz'), [fn1, fn1]); + assert.deepStrictEqual(getEventListeners(emitter, 'foo'), [fn1, fn2]); + assert.deepStrictEqual(getEventListeners(emitter, 'bar'), []); + assert.deepStrictEqual(getEventListeners(emitter, 'baz'), [fn1, fn1]); } // Test getEventListeners on EventTarget { @@ -31,21 +29,21 @@ const { getEventListeners, EventEmitter } = require('events'); target.addEventListener('foo', fn2); target.addEventListener('baz', fn1); target.addEventListener('baz', fn1); - deepStrictEqual(getEventListeners(target, 'foo'), [fn1, fn2]); - deepStrictEqual(getEventListeners(target, 'bar'), []); - deepStrictEqual(getEventListeners(target, 'baz'), [fn1]); + assert.deepStrictEqual(getEventListeners(target, 'foo'), [fn1, fn2]); + assert.deepStrictEqual(getEventListeners(target, 'bar'), []); + assert.deepStrictEqual(getEventListeners(target, 'baz'), [fn1]); } { - throws(() => { + assert.throws(() => { getEventListeners('INVALID_EMITTER'); }, /ERR_INVALID_ARG_TYPE/); } -// { -// // Test weak listeners -// const target = new EventTarget(); -// const fn = common.mustNotCall(); -// target.addEventListener('foo', fn, { [kWeakHandler]: {} }); -// const listeners = getEventListeners(target, 'foo'); -// deepStrictEqual(listeners, [fn]); -// } +{ + // Test weak listeners + const target = new EventTarget(); + const fn = common.mustNotCall(); + target.addEventListener('foo', fn, { [kWeakHandler]: {} }); + const listeners = getEventListeners(target, 'foo'); + assert.deepStrictEqual(listeners, [fn]); +} diff --git a/test/js/node/test/parallel/test-file-write-stream.js b/test/js/node/test/parallel/test-file-write-stream.js index 573cd409db3e..c334d89ccd4a 100644 --- a/test/js/node/test/parallel/test-file-write-stream.js +++ b/test/js/node/test/parallel/test-file-write-stream.js @@ -40,12 +40,12 @@ const callbacks = { }; file - .on('open', function(fd) { + .on('open', common.mustCall((fd) => { console.error('open!'); callbacks.open++; assert.strictEqual(typeof fd, 'number'); - }) - .on('drain', function() { + })) + .on('drain', common.mustCallAtLeast(() => { console.error('drain!', callbacks.drain); callbacks.drain++; if (callbacks.drain === -1) { @@ -55,8 +55,8 @@ file assert.strictEqual(fs.readFileSync(fn, 'utf8'), EXPECTED + EXPECTED); file.end(); } - }) - .on('close', function() { + })) + .on('close', common.mustCall(() => { console.error('close!'); assert.strictEqual(file.bytesWritten, EXPECTED.length * 2); @@ -69,7 +69,7 @@ file file.on('error', common.mustNotCall()); fs.unlinkSync(fn); - }); + })); for (let i = 0; i < 11; i++) { file.write(`${i}`); diff --git a/test/js/node/test/parallel/test-file-write-stream2.js b/test/js/node/test/parallel/test-file-write-stream2.js index ca52135ecf6c..79cdc41c8a26 100644 --- a/test/js/node/test/parallel/test-file-write-stream2.js +++ b/test/js/node/test/parallel/test-file-write-stream2.js @@ -20,7 +20,7 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const fs = require('fs'); @@ -68,13 +68,13 @@ const file = fs.createWriteStream(filepath, { highWaterMark: 11 }); -file.on('open', function(fd) { +file.on('open', common.mustCall((fd) => { console.error('open'); cb_occurred += 'open '; assert.strictEqual(typeof fd, 'number'); -}); +})); -file.on('drain', function() { +file.on('drain', common.mustCallAtLeast(() => { console.error('drain'); cb_occurred += 'drain '; ++countDrains; @@ -88,15 +88,15 @@ file.on('drain', function() { assert.strictEqual(fs.readFileSync(filepath, 'utf8'), EXPECTED + EXPECTED); file.end(); } -}); +})); -file.on('close', function() { +file.on('close', common.mustCall(() => { cb_occurred += 'close '; assert.strictEqual(file.bytesWritten, EXPECTED.length * 2); - file.write('should not work anymore', (err) => { + file.write('should not work anymore', common.mustCall((err) => { assert.ok(err.message.includes('write after end')); - }); -}); + })); +})); for (let i = 0; i < 11; i++) { const ret = file.write(String(i)); diff --git a/test/js/node/test/parallel/test-file-write-stream3.js b/test/js/node/test/parallel/test-file-write-stream3.js index 94ea9bcbc910..0670b078d086 100644 --- a/test/js/node/test/parallel/test-file-write-stream3.js +++ b/test/js/node/test/parallel/test-file-write-stream3.js @@ -65,7 +65,7 @@ function run_test_1() { cb_occurred += 'open '; }); - file.on('close', function() { + file.on('close', common.mustCall(() => { cb_occurred += 'close '; console.log(' (debug: bytesWritten ', file.bytesWritten); console.log(' (debug: start ', file.start); @@ -77,7 +77,7 @@ function run_test_1() { assert.strictEqual(fileData, fileDataExpected_1); run_test_2(); - }); + })); file.on('error', function(err) { cb_occurred += 'error '; @@ -107,7 +107,7 @@ function run_test_2() { cb_occurred += 'open '; }); - file.on('close', function() { + file.on('close', common.mustCall(() => { cb_occurred += 'close '; console.log(' (debug: bytesWritten ', file.bytesWritten); console.log(' (debug: start ', file.start); @@ -119,7 +119,7 @@ function run_test_2() { assert.strictEqual(fileData, fileDataExpected_2); run_test_3(); - }); + })); file.on('error', function(err) { cb_occurred += 'error '; @@ -148,7 +148,7 @@ function run_test_3() { cb_occurred += 'open '; }); - file.on('close', function() { + file.on('close', common.mustCall(() => { cb_occurred += 'close '; console.log(' (debug: bytesWritten ', file.bytesWritten); console.log(' (debug: start ', file.start); @@ -161,7 +161,7 @@ function run_test_3() { run_test_4(); run_test_5(); - }); + })); file.on('error', function(err) { cb_occurred += 'error '; diff --git a/test/js/node/test/parallel/test-filehandle-autoclose.mjs b/test/js/node/test/parallel/test-filehandle-autoclose.mjs index 1b19e968f714..bfc782be56cd 100644 --- a/test/js/node/test/parallel/test-filehandle-autoclose.mjs +++ b/test/js/node/test/parallel/test-filehandle-autoclose.mjs @@ -5,7 +5,7 @@ import assert from 'node:assert'; { const fh = await open(new URL(import.meta.url)); - // autoClose: true is passed explicitly until it becomes the default upstream + // TODO: remove autoClose option when it becomes default const readableStream = fh.readableWebStream({ autoClose: true }); // Consume the stream diff --git a/test/js/node/test/parallel/test-fs-copyfile.js b/test/js/node/test/parallel/test-fs-copyfile.js index 4541ef76b0cb..51d7153de025 100644 --- a/test/js/node/test/parallel/test-fs-copyfile.js +++ b/test/js/node/test/parallel/test-fs-copyfile.js @@ -1,13 +1,15 @@ +// Flags: --expose-internals 'use strict'; const common = require('../common'); const fixtures = require('../common/fixtures'); const tmpdir = require('../common/tmpdir'); const assert = require('assert'); const fs = require('fs'); +const { internalBinding } = require('internal/test/binding'); const { UV_ENOENT, UV_EEXIST -} = process.binding('uv'); +} = internalBinding('uv'); const src = fixtures.path('a.js'); const dest = tmpdir.resolve('copyfile.out'); const { diff --git a/test/js/node/test/parallel/test-fs-error-messages.js b/test/js/node/test/parallel/test-fs-error-messages.js index 270ab97398f0..6db11802f60e 100644 --- a/test/js/node/test/parallel/test-fs-error-messages.js +++ b/test/js/node/test/parallel/test-fs-error-messages.js @@ -42,6 +42,7 @@ fs.writeFileSync(existingFile2, 'test', 'utf-8'); const { COPYFILE_EXCL } = fs.constants; +const { internalBinding } = require('internal/test/binding'); const { UV_EBADF, UV_EEXIST, @@ -50,7 +51,7 @@ const { UV_ENOTDIR, UV_ENOTEMPTY, UV_EPERM -} = process.binding('uv'); +} = internalBinding('uv'); // Template tag function for escaping special characters in strings so that: // new RegExp(re`${str}`).test(str) === true diff --git a/test/js/node/test/parallel/test-fs-promises-file-handle-dispose.js b/test/js/node/test/parallel/test-fs-promises-file-handle-dispose.js index 406430eef4a2..fa1eba0138f6 100644 --- a/test/js/node/test/parallel/test-fs-promises-file-handle-dispose.js +++ b/test/js/node/test/parallel/test-fs-promises-file-handle-dispose.js @@ -1,12 +1,50 @@ 'use strict'; const common = require('../common'); -const { promises: fs } = require('fs'); +const assert = require('assert'); +const { opendirSync, promises: fs } = require('fs'); -async function doOpen() { +async function explicitCall() { const fh = await fs.open(__filename); fh.on('close', common.mustCall()); await fh[Symbol.asyncDispose](); + + const dh = await fs.opendir(__dirname); + await dh[Symbol.asyncDispose](); + // Repeat invocations should not reject + await dh[Symbol.asyncDispose](); + await assert.rejects(dh.read(), { code: 'ERR_DIR_CLOSED' }); + + const dhSync = opendirSync(__dirname); + dhSync[Symbol.dispose](); + // Repeat invocations should not throw + dhSync[Symbol.dispose](); + assert.throws(() => dhSync.readSync(), { code: 'ERR_DIR_CLOSED' }); +} + +async function implicitCall() { + let fh; + { + await using openHandle = await fs.open(__filename); + fh = openHandle; + fh.on('close', common.mustCall()); + } + assert.strictEqual(fh.fd, -1); + + let dh; + { + await using dirHandle = await fs.opendir(__dirname); + dh = dirHandle; + } + await assert.rejects(dh.read(), { code: 'ERR_DIR_CLOSED' }); + + let dhSync; + { + using dirHandleSync = opendirSync(__dirname); + dhSync = dirHandleSync; + } + assert.throws(() => dhSync.readSync(), { code: 'ERR_DIR_CLOSED' }); } -doOpen().then(common.mustCall()); +explicitCall().then(common.mustCall()); +implicitCall().then(common.mustCall()); diff --git a/test/js/node/test/parallel/test-fs-statfs.js b/test/js/node/test/parallel/test-fs-statfs.js index 5fd34f215bc3..4ff66a7d7c0f 100644 --- a/test/js/node/test/parallel/test-fs-statfs.js +++ b/test/js/node/test/parallel/test-fs-statfs.js @@ -7,7 +7,7 @@ function verifyStatFsObject(statfs, isBigint = false) { const valueType = isBigint ? 'bigint' : 'number'; [ - 'type', 'bsize', 'blocks', 'bfree', 'bavail', 'files', 'ffree', + 'type', 'bsize', 'frsize', 'blocks', 'bfree', 'bavail', 'files', 'ffree', ].forEach((k) => { assert.ok(Object.hasOwn(statfs, k)); assert.strictEqual(typeof statfs[k], valueType, @@ -20,11 +20,10 @@ fs.statfs(__filename, common.mustSucceed(function(stats) { assert.strictEqual(this, undefined); })); -fs.statfs(__filename, { bigint: true }, function(err, stats) { - assert.ifError(err); +fs.statfs(__filename, { bigint: true }, common.mustSucceed(function(stats) { verifyStatFsObject(stats, true); assert.strictEqual(this, undefined); -}); +})); // Synchronous { diff --git a/test/js/node/test/parallel/test-fs-utimes.js b/test/js/node/test/parallel/test-fs-utimes.js index e6ae75d4e33a..fc11c0791ddb 100644 --- a/test/js/node/test/parallel/test-fs-utimes.js +++ b/test/js/node/test/parallel/test-fs-utimes.js @@ -63,13 +63,18 @@ function expect_ok(syscall, resource, err, atime, mtime, statSync) { const mtime_diff = check_mtime(resource, mtime, statSync); assert( // Check up to single-second precision. - // Sub-second precision is OS and fs dependant. + // Sub-second precision is OS and fs dependent. !err && (mtime_diff < 2) || err && err.code === 'ENOSYS', `FAILED: expect_ok ${util.inspect(arguments)} check_mtime: ${mtime_diff}` ); } +function getExpectedMtime(mtime) { + // Negative numeric timestamps are normalized to "now" at call time. + return fs._toUnixTimestamp(mtime); +} + const stats = fs.statSync(tmpdir.path); const asPath = (path) => path; @@ -98,11 +103,13 @@ function runTests(iter) { // // test async code paths // + const expectedUtimesMtime = getExpectedMtime(mtime); fs.utimes(pathType(tmpdir.path), atime, mtime, common.mustCall((err) => { - expect_ok('utimes', tmpdir.path, err, atime, mtime); + expect_ok('utimes', tmpdir.path, err, atime, expectedUtimesMtime); + const expectedLutimesMtime = getExpectedMtime(mtime); fs.lutimes(pathType(lpath), atime, mtime, common.mustCall((err) => { - expect_ok('lutimes', lpath, err, atime, mtime, fs.lstatSync); + expect_ok('lutimes', lpath, err, atime, expectedLutimesMtime, fs.lstatSync); fs.utimes(pathType('foobarbaz'), atime, mtime, common.mustCall((err) => { expect_errno('utimes', 'foobarbaz', err, 'ENOENT'); @@ -114,8 +121,9 @@ function runTests(iter) { fd = fs.openSync(tmpdir.path, 'r'); } + const expectedFutimesMtime = getExpectedMtime(mtime); fs.futimes(fd, atime, mtime, common.mustCall((err) => { - expect_ok('futimes', fd, err, atime, mtime); + expect_ok('futimes', fd, err, atime, expectedFutimesMtime); syncTests(); @@ -129,17 +137,20 @@ function runTests(iter) { // test synchronized code paths, these functions throw on failure // function syncTests() { + const expectedUtimesMtime = getExpectedMtime(mtime); fs.utimesSync(pathType(tmpdir.path), atime, mtime); - expect_ok('utimesSync', tmpdir.path, undefined, atime, mtime); + expect_ok('utimesSync', tmpdir.path, undefined, atime, expectedUtimesMtime); + const expectedLutimesMtime = getExpectedMtime(mtime); fs.lutimesSync(pathType(lpath), atime, mtime); - expect_ok('lutimesSync', lpath, undefined, atime, mtime, fs.lstatSync); + expect_ok('lutimesSync', lpath, undefined, atime, expectedLutimesMtime, fs.lstatSync); // Some systems don't have futimes // if there's an error, it should be ENOSYS try { + const expectedFutimesMtime = getExpectedMtime(mtime); fs.futimesSync(fd, atime, mtime); - expect_ok('futimesSync', fd, undefined, atime, mtime); + expect_ok('futimesSync', fd, undefined, atime, expectedFutimesMtime); } catch (ex) { expect_errno('futimesSync', fd, ex, 'ENOSYS'); } diff --git a/test/js/node/test/parallel/test-fs-watch-enoent.js b/test/js/node/test/parallel/test-fs-watch-enoent.js index ef3c6b14008d..e363b3e9325c 100644 --- a/test/js/node/test/parallel/test-fs-watch-enoent.js +++ b/test/js/node/test/parallel/test-fs-watch-enoent.js @@ -12,10 +12,11 @@ const assert = require('assert'); const fs = require('fs'); const tmpdir = require('../common/tmpdir'); const nonexistentFile = tmpdir.resolve('non-existent'); +const { internalBinding } = require('internal/test/binding'); const { UV_ENODEV, UV_ENOENT -} = process.binding('uv'); +} = internalBinding('uv'); tmpdir.refresh(); diff --git a/test/js/node/test/parallel/test-global-encoder.js b/test/js/node/test/parallel/test-global-encoder.js index 0e98bc806ca5..f86d0858ccde 100644 --- a/test/js/node/test/parallel/test-global-encoder.js +++ b/test/js/node/test/parallel/test-global-encoder.js @@ -1,8 +1,8 @@ 'use strict'; require('../common'); -const { strictEqual } = require('assert'); +const assert = require('assert'); const util = require('util'); -strictEqual(TextDecoder, util.TextDecoder); -strictEqual(TextEncoder, util.TextEncoder); +assert.strictEqual(TextDecoder, util.TextDecoder); +assert.strictEqual(TextEncoder, util.TextEncoder); diff --git a/test/js/node/test/parallel/test-icu-stringwidth.js b/test/js/node/test/parallel/test-icu-stringwidth.js index 40ef7a42cd05..66142a8d6811 100644 --- a/test/js/node/test/parallel/test-icu-stringwidth.js +++ b/test/js/node/test/parallel/test-icu-stringwidth.js @@ -51,7 +51,7 @@ assert.strictEqual(getStringWidth(String.fromCharCode(0x20DD)), 0); // these fully. // See https://www.unicode.org/reports/tr51/tr51-16.html#Emoji_ZWJ_Sequences assert.strictEqual(getStringWidth('👩‍👩‍👧‍👧'), 8); -// Upstream note (BridgeAR): This should have a width of two and six. The heart contains +// TODO(BridgeAR): This should have a width of two and six. The heart contains // the \uFE0F variation selector that indicates that it should be displayed as // emoji instead of as text. Emojis are all full width characters when not being // rendered as text. diff --git a/test/js/node/test/parallel/test-kill-segfault-freebsd.js b/test/js/node/test/parallel/test-kill-segfault-freebsd.js index e17b00741bd9..baba07f3f151 100644 --- a/test/js/node/test/parallel/test-kill-segfault-freebsd.js +++ b/test/js/node/test/parallel/test-kill-segfault-freebsd.js @@ -1,5 +1,5 @@ 'use strict'; -require('../common'); +const common = require('../common'); // This test ensures Node.js doesn't crash on hitting Ctrl+C in order to // terminate the currently running process (especially on FreeBSD). @@ -14,6 +14,6 @@ const cp = child_process.spawn(process.execPath, [ 'process.kill(process.pid, "SIGINT")', ]); -cp.on('exit', function(code) { +cp.on('exit', common.mustCall((code) => { assert.notStrictEqual(code, 0); -}); +})); diff --git a/test/js/node/test/parallel/test-listen-fd-detached-inherit.js b/test/js/node/test/parallel/test-listen-fd-detached-inherit.js index 2a8e70f0f942..3c87794d073a 100644 --- a/test/js/node/test/parallel/test-listen-fd-detached-inherit.js +++ b/test/js/node/test/parallel/test-listen-fd-detached-inherit.js @@ -58,12 +58,12 @@ function test() { server: 'localhost', port: child.port, path: '/', - }).on('response', function(res) { + }).on('response', common.mustCall((res) => { let s = ''; res.on('data', function(c) { s += c.toString(); }); - res.on('end', function() { + res.on('end', common.mustCall(() => { // Kill the subprocess before we start doing asserts. // It's really annoying when tests leave orphans! process.kill(child.pid, 'SIGKILL'); @@ -75,8 +75,8 @@ function test() { assert.strictEqual(s, 'hello from child\n'); assert.strictEqual(res.statusCode, 200); - }); - }); + })); + })); } } diff --git a/test/js/node/test/parallel/test-listen-fd-detached.js b/test/js/node/test/parallel/test-listen-fd-detached.js index fba96a112f89..4506bd4ab8f9 100644 --- a/test/js/node/test/parallel/test-listen-fd-detached.js +++ b/test/js/node/test/parallel/test-listen-fd-detached.js @@ -58,12 +58,12 @@ function test() { server: 'localhost', port: child.port, path: '/', - }).on('response', function(res) { + }).on('response', common.mustCall((res) => { let s = ''; res.on('data', function(c) { s += c.toString(); }); - res.on('end', function() { + res.on('end', common.mustCall(() => { // Kill the subprocess before we start doing asserts. // it's really annoying when tests leave orphans! process.kill(child.pid, 'SIGKILL'); @@ -75,8 +75,8 @@ function test() { assert.strictEqual(s, 'hello from child\n'); assert.strictEqual(res.statusCode, 200); - }); - }); + })); + })); } } diff --git a/test/js/node/test/parallel/test-microtask-queue-run-immediate.js b/test/js/node/test/parallel/test-microtask-queue-run-immediate.js index 577391993bcc..52f4cd5bd7e3 100644 --- a/test/js/node/test/parallel/test-microtask-queue-run-immediate.js +++ b/test/js/node/test/parallel/test-microtask-queue-run-immediate.js @@ -24,6 +24,7 @@ require('../common'); const assert = require('assert'); function enqueueMicrotask(fn) { + // eslint-disable-next-line node-core/must-call-assert Promise.resolve().then(fn); } diff --git a/test/js/node/test/parallel/test-microtask-queue-run.js b/test/js/node/test/parallel/test-microtask-queue-run.js index 5281cb4f3c2e..4d3156affe96 100644 --- a/test/js/node/test/parallel/test-microtask-queue-run.js +++ b/test/js/node/test/parallel/test-microtask-queue-run.js @@ -24,6 +24,7 @@ require('../common'); const assert = require('assert'); function enqueueMicrotask(fn) { + // eslint-disable-next-line node-core/must-call-assert Promise.resolve().then(fn); } diff --git a/test/js/node/test/parallel/test-module-prototype-mutation.js b/test/js/node/test/parallel/test-module-prototype-mutation.js index d0149548600f..6d83533a5ed2 100644 --- a/test/js/node/test/parallel/test-module-prototype-mutation.js +++ b/test/js/node/test/parallel/test-module-prototype-mutation.js @@ -49,4 +49,4 @@ assert.strictEqual( ); import(fixtures.fileURL('es-module-specifiers', 'index.mjs')) - .then(common.mustCall((module) => assert.strictEqual(module.noMain, 'no main field'))); + .then(common.mustCall((module) => { assert.strictEqual(module.noMain, 'no main field'); })); diff --git a/test/js/node/test/parallel/test-module-run-main-monkey-patch.js b/test/js/node/test/parallel/test-module-run-main-monkey-patch.js index c9f189abb688..bafb91ffeffd 100644 --- a/test/js/node/test/parallel/test-module-run-main-monkey-patch.js +++ b/test/js/node/test/parallel/test-module-run-main-monkey-patch.js @@ -4,14 +4,14 @@ // TODO(joyeecheung): This probably should be deprecated. require('../common'); -const { path } = require('../common/fixtures'); +const fixtures = require('../common/fixtures'); const assert = require('assert'); const { spawnSync } = require('child_process'); const child = spawnSync(process.execPath, [ '--require', - path('monkey-patch-run-main.js'), - path('semicolon.js'), + fixtures.path('monkey-patch-run-main.js'), + fixtures.path('semicolon.js'), ]); assert.strictEqual(child.status, 0); diff --git a/test/js/node/test/parallel/test-module-stat.js b/test/js/node/test/parallel/test-module-stat.js index 0ab63f8edf95..a15365b784eb 100644 --- a/test/js/node/test/parallel/test-module-stat.js +++ b/test/js/node/test/parallel/test-module-stat.js @@ -6,7 +6,7 @@ require('../common'); const Module = require('module'); const fs = require('fs'); const tmpdir = require('../common/tmpdir'); -const { ok, strictEqual } = require('assert'); +const assert = require('assert'); const directory = tmpdir.resolve('directory'); const doesNotExist = tmpdir.resolve('does-not-exist'); @@ -16,9 +16,9 @@ tmpdir.refresh(); fs.writeFileSync(file, "module.exports = { a: 'b' }"); fs.mkdirSync(directory); -strictEqual(Module._stat(directory), 1); // Returns 1 for directories. -strictEqual(Module._stat(file), 0); // Returns 0 for files. -ok(Module._stat(doesNotExist) < 0); // Returns a negative integer for any other kind of strings. +assert.strictEqual(Module._stat(directory), 1); // Returns 1 for directories. +assert.strictEqual(Module._stat(file), 0); // Returns 0 for files. +assert.ok(Module._stat(doesNotExist) < 0); // Returns a negative integer for any other kind of strings. // TODO(RaisinTen): Add tests that make sure that Module._stat() does not crash when called // with a non-string data type. It crashes currently. diff --git a/test/js/node/test/parallel/test-net-autoselectfamily-default.js b/test/js/node/test/parallel/test-net-autoselectfamily-default.js index b0b41fb7037d..67977498c5a3 100644 --- a/test/js/node/test/parallel/test-net-autoselectfamily-default.js +++ b/test/js/node/test/parallel/test-net-autoselectfamily-default.js @@ -10,12 +10,12 @@ const autoSelectFamilyAttemptTimeout = common.defaultAutoSelectFamilyAttemptTime // Test that IPV4 is reached by default if IPV6 is not reachable and the default is enabled { - const ipv4Server = createServer((socket) => { + const ipv4Server = createServer(common.mustCall((socket) => { socket.on('data', common.mustCall(() => { socket.write('response-ipv4'); socket.end(); })); - }); + })); ipv4Server.listen(0, '127.0.0.1', common.mustCall(() => { setDefaultAutoSelectFamily(true); @@ -45,12 +45,12 @@ const autoSelectFamilyAttemptTimeout = common.defaultAutoSelectFamilyAttemptTime // Test that IPV4 is not reached by default if IPV6 is not reachable and the default is disabled { - const ipv4Server = createServer((socket) => { + const ipv4Server = createServer(common.mustCallAtLeast((socket) => { socket.on('data', common.mustCall(() => { socket.write('response-ipv4'); socket.end(); })); - }); + }, 0)); ipv4Server.listen(0, '127.0.0.1', common.mustCall(() => { setDefaultAutoSelectFamily(false); diff --git a/test/js/node/test/parallel/test-net-autoselectfamily-ipv4first.js b/test/js/node/test/parallel/test-net-autoselectfamily-ipv4first.js index f94af0d9eeeb..e7e788a0d219 100644 --- a/test/js/node/test/parallel/test-net-autoselectfamily-ipv4first.js +++ b/test/js/node/test/parallel/test-net-autoselectfamily-ipv4first.js @@ -8,12 +8,12 @@ const { createConnection, createServer } = require('net'); // Test that happy eyeballs algorithm is properly implemented when a A record is returned first. if (common.hasIPv6) { - const ipv4Server = createServer((socket) => { + const ipv4Server = createServer(common.mustCall((socket) => { socket.on('data', common.mustCall(() => { socket.write('response-ipv4'); socket.end(); })); - }); + })); const ipv6Server = createServer((socket) => { socket.on('data', common.mustNotCall(() => { diff --git a/test/js/node/test/parallel/test-net-blocklist.js b/test/js/node/test/parallel/test-net-blocklist.js index 901b9a4dfb7b..7048405aa97f 100644 --- a/test/js/node/test/parallel/test-net-blocklist.js +++ b/test/js/node/test/parallel/test-net-blocklist.js @@ -3,7 +3,6 @@ const common = require('../common'); const net = require('net'); const assert = require('assert'); - const blockList = new net.BlockList(); blockList.addAddress('127.0.0.1'); blockList.addAddress('127.0.0.2'); diff --git a/test/js/node/test/parallel/test-net-child-process-connect-reset.js b/test/js/node/test/parallel/test-net-child-process-connect-reset.js index 228ba8ed57fc..ef9245c910ed 100644 --- a/test/js/node/test/parallel/test-net-child-process-connect-reset.js +++ b/test/js/node/test/parallel/test-net-child-process-connect-reset.js @@ -35,10 +35,10 @@ if (process.argv[2] === 'child') { } }); - conn.on('error', (err) => { + conn.on('error', common.mustCallAtLeast((err) => { // Error emitted on Windows. assert.strictEqual(err.code, 'ECONNRESET'); - }); + }, 0)); conn.on('connect', common.mustCall(() => { cp.kill('SIGKILL'); diff --git a/test/js/node/test/parallel/test-net-connect-abort-controller.js b/test/js/node/test/parallel/test-net-connect-abort-controller.js index 9c259cc3fc2c..3d2b19615044 100644 --- a/test/js/node/test/parallel/test-net-connect-abort-controller.js +++ b/test/js/node/test/parallel/test-net-connect-abort-controller.js @@ -3,7 +3,7 @@ const common = require('../common'); const net = require('net'); const assert = require('assert'); const server = net.createServer(); -const { getEventListeners, once } = require('events'); +const { listenerCount, once } = require('events'); const liveConnections = new Set(); @@ -18,20 +18,20 @@ server.listen(0, common.mustCall(async () => { }); }); - const assertAbort = async (socket, testName) => { + const assertAbort = common.mustCallAtLeast(async (socket, testName) => { try { await once(socket, 'close'); assert.fail(`close ${testName} should have thrown`); } catch (err) { assert.strictEqual(err.name, 'AbortError'); } - }; + }); async function postAbort() { const ac = new AbortController(); const { signal } = ac; const socket = net.connect(socketOptions(signal)); - assert.strictEqual(getEventListeners(signal, 'abort').length, 1); + assert.strictEqual(listenerCount(signal, 'abort'), 1); ac.abort(); await assertAbort(socket, 'postAbort'); } @@ -41,7 +41,7 @@ server.listen(0, common.mustCall(async () => { const { signal } = ac; ac.abort(); const socket = net.connect(socketOptions(signal)); - assert.strictEqual(getEventListeners(signal, 'abort').length, 0); + assert.strictEqual(listenerCount(signal, 'abort'), 0); await assertAbort(socket, 'preAbort'); } @@ -50,7 +50,7 @@ server.listen(0, common.mustCall(async () => { const { signal } = ac; setImmediate(() => ac.abort()); const socket = net.connect(socketOptions(signal)); - assert.strictEqual(getEventListeners(signal, 'abort').length, 1); + assert.strictEqual(listenerCount(signal, 'abort'), 1); await assertAbort(socket, 'tickAbort'); } @@ -59,7 +59,7 @@ server.listen(0, common.mustCall(async () => { const { signal } = ac; ac.abort(); const socket = new net.Socket(socketOptions(signal)); - assert.strictEqual(getEventListeners(signal, 'abort').length, 0); + assert.strictEqual(listenerCount(signal, 'abort'), 0); await assertAbort(socket, 'testConstructor'); } @@ -67,7 +67,7 @@ server.listen(0, common.mustCall(async () => { const ac = new AbortController(); const { signal } = ac; const socket = new net.Socket(socketOptions(signal)); - assert.strictEqual(getEventListeners(signal, 'abort').length, 1); + assert.strictEqual(listenerCount(signal, 'abort'), 1); ac.abort(); await assertAbort(socket, 'testConstructorPost'); } @@ -76,7 +76,7 @@ server.listen(0, common.mustCall(async () => { const ac = new AbortController(); const { signal } = ac; const socket = new net.Socket(socketOptions(signal)); - assert.strictEqual(getEventListeners(signal, 'abort').length, 1); + assert.strictEqual(listenerCount(signal, 'abort'), 1); setImmediate(() => ac.abort()); await assertAbort(socket, 'testConstructorPostTick'); } diff --git a/test/js/node/test/parallel/test-net-connect-nodelay.js b/test/js/node/test/parallel/test-net-connect-nodelay.js index 6810e339e2b6..ede4ae480534 100644 --- a/test/js/node/test/parallel/test-net-connect-nodelay.js +++ b/test/js/node/test/parallel/test-net-connect-nodelay.js @@ -6,9 +6,6 @@ const net = require('net'); const truthyValues = [true, 1, 'true', {}, []]; const falseyValues = [false, 0, '']; -const genSetNoDelay = (desiredArg) => (enable) => { - assert.strictEqual(enable, desiredArg); -}; for (const value of truthyValues) { const server = net.createServer(); @@ -21,7 +18,9 @@ for (const value of truthyValues) { common.mustCall(() => client.end()) ); - client._handle.setNoDelay = common.mustCall(genSetNoDelay(true)); + client._handle.setNoDelay = common.mustCall((enable) => { + assert.strictEqual(enable, true); + }); client.on('end', common.mustCall(function() { server.close(); diff --git a/test/js/node/test/parallel/test-net-connect-options-invalid.js b/test/js/node/test/parallel/test-net-connect-options-invalid.js index 53ce89cac9aa..3c748b151610 100644 --- a/test/js/node/test/parallel/test-net-connect-options-invalid.js +++ b/test/js/node/test/parallel/test-net-connect-options-invalid.js @@ -35,6 +35,5 @@ const net = require('net'); }, { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', - message: 'The "options.host" property must be of type string. Received an instance of Array', }); } diff --git a/test/js/node/test/parallel/test-net-connect-options-port.js b/test/js/node/test/parallel/test-net-connect-options-port.js index b62fe9457842..c46dbb88aa51 100644 --- a/test/js/node/test/parallel/test-net-connect-options-port.js +++ b/test/js/node/test/parallel/test-net-connect-options-port.js @@ -171,7 +171,7 @@ function syncFailToConnect(port, assertErr, optOnly) { } function canConnect(port) { - const noop = () => common.mustCall(); + const noop = common.mustCallAtLeast(() => common.mustCall()); const family = 4; // connect(port, cb) and connect(port) @@ -202,10 +202,10 @@ function canConnect(port) { } function asyncFailToConnect(port) { - const onError = () => common.mustCall((err) => { + const onError = common.mustCallAtLeast(() => common.mustCall((err) => { const regexp = /^Error: connect E\w+.+$/; assert.match(String(err), regexp); - }); + })); const dont = () => common.mustNotCall(); const family = 4; diff --git a/test/js/node/test/parallel/test-net-eaddrinuse.js b/test/js/node/test/parallel/test-net-eaddrinuse.js index 8bd790158e36..dd13ed1ee466 100644 --- a/test/js/node/test/parallel/test-net-eaddrinuse.js +++ b/test/js/node/test/parallel/test-net-eaddrinuse.js @@ -27,9 +27,9 @@ const net = require('net'); const server1 = net.createServer(common.mustNotCall()); const server2 = net.createServer(common.mustNotCall()); server1.listen(0, common.mustCall(function() { - server2.on('error', function(error) { - assert.strictEqual(error.code === 'EADDRINUSE', true); + server2.on('error', common.mustCall((error) => { + assert.strictEqual(error.message.includes('EADDRINUSE'), true); server1.close(); - }); + })); server2.listen(this.address().port); })); diff --git a/test/js/node/test/parallel/test-net-keepalive.js b/test/js/node/test/parallel/test-net-keepalive.js index d91ec625f882..26a4c5b3d648 100644 --- a/test/js/node/test/parallel/test-net-keepalive.js +++ b/test/js/node/test/parallel/test-net-keepalive.js @@ -26,7 +26,7 @@ const net = require('net'); let serverConnection; let clientConnection; -const echoServer = net.createServer(function(connection) { +const echoServer = net.createServer(common.mustCall((connection) => { serverConnection = connection; setTimeout(common.mustCall(function() { // Make sure both connections are still open @@ -43,7 +43,7 @@ const echoServer = net.createServer(function(connection) { connection.on('end', function() { connection.end(); }); -}); +})); echoServer.listen(0); echoServer.on('listening', function() { diff --git a/test/js/node/test/parallel/test-net-listen-exclusive-random-ports.js b/test/js/node/test/parallel/test-net-listen-exclusive-random-ports.js index 66dfb598204e..3604e2481ccd 100644 --- a/test/js/node/test/parallel/test-net-listen-exclusive-random-ports.js +++ b/test/js/node/test/parallel/test-net-listen-exclusive-random-ports.js @@ -1,6 +1,6 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const cluster = require('cluster'); const net = require('net'); @@ -8,19 +8,19 @@ const net = require('net'); if (cluster.isPrimary) { const worker1 = cluster.fork(); - worker1.on('message', function(port1) { + worker1.on('message', common.mustCall((port1) => { assert.strictEqual(port1, port1 | 0, `first worker could not listen on port ${port1}`); const worker2 = cluster.fork(); - worker2.on('message', function(port2) { + worker2.on('message', common.mustCall((port2) => { assert.strictEqual(port2, port2 | 0, `second worker could not listen on port ${port2}`); - assert.notStrictEqual(port1, port2, 'ports should not be equal'); + assert.notStrictEqual(port1, port2); worker1.kill(); worker2.kill(); - }); - }); + })); + })); } else { const server = net.createServer(() => {}); diff --git a/test/js/node/test/parallel/test-net-listen-invalid-port.js b/test/js/node/test/parallel/test-net-listen-invalid-port.js index 844878036646..220ca2ba30b0 100644 --- a/test/js/node/test/parallel/test-net-listen-invalid-port.js +++ b/test/js/node/test/parallel/test-net-listen-invalid-port.js @@ -10,13 +10,13 @@ const net = require('net'); const invalidPort = -1 >>> 0; -net.Server().listen(0, function() { +net.Server().listen(0, common.mustCall(function() { const address = this.address(); const key = `${address.family.slice(-1)}:${address.address}:0`; assert.strictEqual(this._connectionKey, key); this.close(); -}); +})); // The first argument is a configuration object assert.throws(() => { diff --git a/test/js/node/test/parallel/test-net-localerror.js b/test/js/node/test/parallel/test-net-localerror.js index 92095340512d..ab31c992556e 100644 --- a/test/js/node/test/parallel/test-net-localerror.js +++ b/test/js/node/test/parallel/test-net-localerror.js @@ -20,16 +20,16 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const net = require('net'); -const connect = (opts, code, type) => { +const connect = common.mustCall((opts, code, type) => { assert.throws( () => net.connect(opts), { code, name: type.name } ); -}; +}, 2); connect({ host: 'localhost', diff --git a/test/js/node/test/parallel/test-net-pipe-connect-errors.js b/test/js/node/test/parallel/test-net-pipe-connect-errors.js index fec4259b348d..33dc6a8a23b5 100644 --- a/test/js/node/test/parallel/test-net-pipe-connect-errors.js +++ b/test/js/node/test/parallel/test-net-pipe-connect-errors.js @@ -24,6 +24,7 @@ const common = require('../common'); const fixtures = require('../common/fixtures'); const fs = require('fs'); const net = require('net'); +const path = require('path'); const assert = require('assert'); // Test if ENOTSOCK is fired when trying to connect to a file which is not @@ -38,11 +39,11 @@ if (common.isWindows) { } else { const tmpdir = require('../common/tmpdir'); tmpdir.refresh(); - // Keep the file name very short so that we don't exceed the 108 char limit - // on CI for a POSIX socket. Even though this isn't actually a socket file, - // the error will be different from the one we are expecting if we exceed the - // limit. - emptyTxt = `${tmpdir.path}0.txt`; + // Use a short relative path so that we don't exceed the 108 byte limit for + // Unix socket paths in long or multibyte CI workspaces. Even though this + // isn't actually a socket file, the error will be different from the one we + // are expecting if the path is too long. + emptyTxt = path.join(path.relative(process.cwd(), tmpdir.path), '0.txt'); function cleanup() { try { diff --git a/test/js/node/test/parallel/test-net-reconnect.js b/test/js/node/test/parallel/test-net-reconnect.js index 233f5b01e544..2f7de82eb442 100644 --- a/test/js/node/test/parallel/test-net-reconnect.js +++ b/test/js/node/test/parallel/test-net-reconnect.js @@ -20,7 +20,7 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const net = require('net'); @@ -30,7 +30,7 @@ let client_recv_count = 0; let client_end_count = 0; let disconnect_count = 0; -const server = net.createServer(function(socket) { +const server = net.createServer(common.mustCallAtLeast((socket) => { console.error('SERVER: got socket connection'); socket.resume(); @@ -42,13 +42,13 @@ const server = net.createServer(function(socket) { socket.end(); }); - socket.on('close', (had_error) => { + socket.on('close', common.mustCall((had_error) => { console.log(`SERVER had_error: ${JSON.stringify(had_error)}`); assert.strictEqual(had_error, false); - }); -}); + })); +})); -server.listen(0, function() { +server.listen(0, common.mustCall(function() { console.log('SERVER listening'); const client = net.createConnection(this.address().port); @@ -58,28 +58,28 @@ server.listen(0, function() { console.error('CLIENT connected', client._writableState); }); - client.on('data', function(chunk) { + client.on('data', common.mustCallAtLeast((chunk) => { client_recv_count += 1; console.log(`client_recv_count ${client_recv_count}`); assert.strictEqual(chunk, 'hello\r\n'); console.error('CLIENT: calling end', client._writableState); client.end(); - }); + })); client.on('end', () => { console.error('CLIENT end'); client_end_count++; }); - client.on('close', (had_error) => { + client.on('close', common.mustCallAtLeast((had_error) => { console.log('CLIENT disconnect'); assert.strictEqual(had_error, false); if (disconnect_count++ < N) client.connect(server.address().port); // reconnect else server.close(); - }); -}); + })); +})); process.on('exit', () => { assert.strictEqual(disconnect_count, N + 1); diff --git a/test/js/node/test/parallel/test-net-remote-address-port.js b/test/js/node/test/parallel/test-net-remote-address-port.js index 615f22979c2f..7a3561950146 100644 --- a/test/js/node/test/parallel/test-net-remote-address-port.js +++ b/test/js/node/test/parallel/test-net-remote-address-port.js @@ -43,14 +43,14 @@ const server = net.createServer(common.mustCall(function(socket) { socket.on('end', function() { if (++conns_closed === 2) server.close(); }); - socket.on('close', function() { + socket.on('close', common.mustCall(() => { assert.ok(remoteAddrCandidates.includes(socket.remoteAddress)); assert.ok(remoteFamilyCandidates.includes(socket.remoteFamily)); - }); + })); socket.resume(); }, 2)); -server.listen(0, function() { +server.listen(0, common.mustCall(function() { const client = net.createConnection(this.address().port, '127.0.0.1'); const client2 = net.createConnection(this.address().port); @@ -61,24 +61,24 @@ server.listen(0, function() { assert.strictEqual(client2.remoteFamily, undefined); assert.strictEqual(client2.remotePort, undefined); - client.on('connect', function() { + client.on('connect', common.mustCall(() => { assert.ok(remoteAddrCandidates.includes(client.remoteAddress)); assert.ok(remoteFamilyCandidates.includes(client.remoteFamily)); assert.strictEqual(client.remotePort, server.address().port); client.end(); - }); - client.on('close', function() { + })); + client.on('close', common.mustCall(() => { assert.ok(remoteAddrCandidates.includes(client.remoteAddress)); assert.ok(remoteFamilyCandidates.includes(client.remoteFamily)); - }); - client2.on('connect', function() { + })); + client2.on('connect', common.mustCall(() => { assert.ok(remoteAddrCandidates.includes(client2.remoteAddress)); assert.ok(remoteFamilyCandidates.includes(client2.remoteFamily)); assert.strictEqual(client2.remotePort, server.address().port); client2.end(); - }); - client2.on('close', function() { + })); + client2.on('close', common.mustCall(() => { assert.ok(remoteAddrCandidates.includes(client2.remoteAddress)); assert.ok(remoteFamilyCandidates.includes(client2.remoteFamily)); - }); -}); + })); +})); diff --git a/test/js/node/test/parallel/test-net-remote-address.js b/test/js/node/test/parallel/test-net-remote-address.js index a116cb99d3bc..904e8dcccb56 100644 --- a/test/js/node/test/parallel/test-net-remote-address.js +++ b/test/js/node/test/parallel/test-net-remote-address.js @@ -2,18 +2,18 @@ const common = require('../common'); const net = require('net'); -const { strictEqual } = require('assert'); +const assert = require('assert'); const server = net.createServer(); server.listen(common.mustCall(function() { const socket = net.connect({ port: server.address().port }); - strictEqual(socket.connecting, true); - strictEqual(socket.remoteAddress, undefined); + assert.strictEqual(socket.connecting, true); + assert.strictEqual(socket.remoteAddress, undefined); socket.on('connect', common.mustCall(function() { - strictEqual(socket.remoteAddress !== undefined, true); + assert.strictEqual(socket.remoteAddress !== undefined, true); socket.end(); })); diff --git a/test/js/node/test/parallel/test-net-server-close.js b/test/js/node/test/parallel/test-net-server-close.js index 8291f70432ec..ff08150bbf17 100644 --- a/test/js/node/test/parallel/test-net-server-close.js +++ b/test/js/node/test/parallel/test-net-server-close.js @@ -26,7 +26,7 @@ const net = require('net'); const sockets = []; -const server = net.createServer(function(c) { +const server = net.createServer(common.mustCallAtLeast((c) => { c.on('close', common.mustCall()); sockets.push(c); @@ -35,7 +35,7 @@ const server = net.createServer(function(c) { assert.strictEqual(server.close(), server); sockets.forEach((c) => c.destroy()); } -}); +})); server.on('close', common.mustCall()); diff --git a/test/js/node/test/parallel/test-net-server-listen-remove-callback.js b/test/js/node/test/parallel/test-net-server-listen-remove-callback.js index a874099fb8c7..87bd7448aef1 100644 --- a/test/js/node/test/parallel/test-net-server-listen-remove-callback.js +++ b/test/js/node/test/parallel/test-net-server-listen-remove-callback.js @@ -20,18 +20,18 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const net = require('net'); // Server should only fire listen callback once const server = net.createServer(); -server.on('close', function() { +server.on('close', common.mustCall(() => { const listeners = server.listeners('listening'); console.log('Closed, listeners:', listeners.length); assert.strictEqual(listeners.length, 0); -}); +}, 2)); server.listen(0, function() { server.close(); diff --git a/test/js/node/test/parallel/test-net-server-max-connections-close-makes-more-available.js b/test/js/node/test/parallel/test-net-server-max-connections-close-makes-more-available.js index f607f28c10ea..408fb4a01ee3 100644 --- a/test/js/node/test/parallel/test-net-server-max-connections-close-makes-more-available.js +++ b/test/js/node/test/parallel/test-net-server-max-connections-close-makes-more-available.js @@ -1,5 +1,5 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const net = require('net'); @@ -28,10 +28,10 @@ function createConnection(index) { sent.push(msg); }); - connection.on('error', function(err) { + connection.on('error', common.mustCallAtLeast((err) => { assert.strictEqual(err.code, 'ECONNRESET'); resolve(); - }); + }, 0)); connection.on('data', function(e) { console.error(`connection ${index} received response`); @@ -67,15 +67,16 @@ const server = net.createServer(function(socket) { server.maxConnections = 1; -server.listen(0, function() { +server.listen(0, common.mustCall(() => { createConnection(0) .then(createConnection.bind(null, 1)) .then(closeConnection.bind(null, 0)) .then(createConnection.bind(null, 2)) .then(createConnection.bind(null, 3)) .then(server.close.bind(server)) - .then(closeConnection.bind(null, 2)); -}); + .then(closeConnection.bind(null, 2)) + .then(common.mustCall()); +})); process.on('exit', function() { // Confirm that all connections tried to send data... diff --git a/test/js/node/test/parallel/test-net-server-max-connections.js b/test/js/node/test/parallel/test-net-server-max-connections.js index ea9a8d29e9f1..4e347de7892c 100644 --- a/test/js/node/test/parallel/test-net-server-max-connections.js +++ b/test/js/node/test/parallel/test-net-server-max-connections.js @@ -49,12 +49,12 @@ function makeConnection(index) { const c = net.createConnection(server.address().port); let gotData = false; - c.on('connect', function() { + c.on('connect', common.mustCall(() => { if (index + 1 < N) { makeConnection(index + 1); } - c.on('close', function() { + c.on('close', common.mustCall(() => { console.error(`closed ${index}`); closes++; @@ -81,15 +81,15 @@ function makeConnection(index) { assert.strictEqual(gotData, false, `${index} got data, but shouldn't have`); } - }); - }); + })); + })); c.on('end', function() { c.end(); }); - c.on('data', function(b) { + c.on('data', common.mustCallAtLeast((b) => { gotData = true; assert.ok(b.length > 0); - }); + }, 0)); c.on('error', function(e) { // Retry if SmartOS and ECONNREFUSED. See diff --git a/test/js/node/test/parallel/test-net-server-pause-on-connect.js b/test/js/node/test/parallel/test-net-server-pause-on-connect.js index 59c39e8816cc..51bdec9ac641 100644 --- a/test/js/node/test/parallel/test-net-server-pause-on-connect.js +++ b/test/js/node/test/parallel/test-net-server-pause-on-connect.js @@ -28,8 +28,8 @@ let stopped = true; let server1Sock; -const server1ConnHandler = (socket) => { - socket.on('data', function(data) { +const server1ConnHandler = common.mustCall((socket) => { + socket.on('data', common.mustCall((data) => { if (stopped) { assert.fail('data event should not have happened yet'); } @@ -37,15 +37,15 @@ const server1ConnHandler = (socket) => { assert.strictEqual(data.toString(), msg); socket.end(); server1.close(); - }); + })); server1Sock = socket; -}; +}); const server1 = net.createServer({ pauseOnConnect: true }, server1ConnHandler); -const server2ConnHandler = (socket) => { - socket.on('data', function(data) { +const server2ConnHandler = common.mustCall((socket) => { + socket.on('data', common.mustCall((data) => { assert.strictEqual(data.toString(), msg); socket.end(); server2.close(); @@ -53,19 +53,19 @@ const server2ConnHandler = (socket) => { assert.strictEqual(server1Sock.bytesRead, 0); server1Sock.resume(); stopped = false; - }); -}; + })); +}); const server2 = net.createServer({ pauseOnConnect: false }, server2ConnHandler); -server1.listen(0, function() { +server1.listen(0, common.mustCall(function() { const clientHandler = common.mustCall(function() { server2.listen(0, function() { net.createConnection({ port: this.address().port }).write(msg); }); }); net.createConnection({ port: this.address().port }).write(msg, clientHandler); -}); +})); process.on('exit', function() { assert.strictEqual(stopped, false); diff --git a/test/js/node/test/parallel/test-net-settimeout.js b/test/js/node/test/parallel/test-net-settimeout.js index 581e27ec327d..5662a5cc4140 100644 --- a/test/js/node/test/parallel/test-net-settimeout.js +++ b/test/js/node/test/parallel/test-net-settimeout.js @@ -33,7 +33,7 @@ const server = net.createServer(common.mustCall((c) => { c.write('hello'); })); -server.listen(0, function() { +server.listen(0, common.mustCall(function() { const socket = net.createConnection(this.address().port, 'localhost'); const s = socket.setTimeout(T, common.mustNotCall()); @@ -47,4 +47,4 @@ server.listen(0, function() { })); socket.setTimeout(0); -}); +})); diff --git a/test/js/node/test/parallel/test-net-socket-close-after-end.js b/test/js/node/test/parallel/test-net-socket-close-after-end.js index 06bf55f89d6e..4b86849c1e83 100644 --- a/test/js/node/test/parallel/test-net-socket-close-after-end.js +++ b/test/js/node/test/parallel/test-net-socket-close-after-end.js @@ -6,7 +6,7 @@ const net = require('net'); const server = net.createServer(); -server.on('connection', (socket) => { +server.on('connection', common.mustCall((socket) => { let endEmitted = false; socket.once('readable', () => { @@ -17,12 +17,12 @@ server.on('connection', (socket) => { socket.on('end', () => { endEmitted = true; }); - socket.on('close', () => { + socket.on('close', common.mustCall(() => { assert(endEmitted); server.close(); - }); + })); socket.end('foo'); -}); +})); server.listen(common.mustCall(() => { const socket = net.createConnection(server.address().port, () => { diff --git a/test/js/node/test/parallel/test-net-socket-connecting.js b/test/js/node/test/parallel/test-net-socket-connecting.js index 21aa261192c1..222361a8843e 100644 --- a/test/js/node/test/parallel/test-net-socket-connecting.js +++ b/test/js/node/test/parallel/test-net-socket-connecting.js @@ -1,21 +1,21 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const net = require('net'); const server = net.createServer((conn) => { conn.end(); server.close(); -}).listen(0, () => { - const client = net.connect(server.address().port, () => { +}).listen(0, common.mustCall(() => { + const client = net.connect(server.address().port, common.mustCall(() => { assert.strictEqual(client.connecting, false); // Legacy getter assert.strictEqual(client._connecting, false); client.end(); - }); + })); assert.strictEqual(client.connecting, true); // Legacy getter assert.strictEqual(client._connecting, true); -}); +})); diff --git a/test/js/node/test/parallel/test-net-socket-no-halfopen-enforcer.js b/test/js/node/test/parallel/test-net-socket-no-halfopen-enforcer.js index 3df5b6d7b9c8..69ebd694e8fa 100644 --- a/test/js/node/test/parallel/test-net-socket-no-halfopen-enforcer.js +++ b/test/js/node/test/parallel/test-net-socket-no-halfopen-enforcer.js @@ -5,7 +5,7 @@ require('../common'); // enforcer from `stream.Duplex`. const { Socket } = require('net'); -const { strictEqual } = require('assert'); +const assert = require('assert'); const socket = new Socket({ allowHalfOpen: false }); -strictEqual(socket.listenerCount('end'), 1); +assert.strictEqual(socket.listenerCount('end'), 1); diff --git a/test/js/node/test/parallel/test-net-socket-write-error.js b/test/js/node/test/parallel/test-net-socket-write-error.js index e68db68c0d49..c181c9ce9011 100644 --- a/test/js/node/test/parallel/test-net-socket-write-error.js +++ b/test/js/node/test/parallel/test-net-socket-write-error.js @@ -7,7 +7,7 @@ const assert = require('assert'); const server = net.createServer().listen(0, connectToServer); function connectToServer() { - const client = net.createConnection(this.address().port, () => { + const client = net.createConnection(this.address().port, common.mustCall(() => { client.on('error', common.mustNotCall()); assert.throws(() => { client.write(1337); @@ -17,6 +17,6 @@ function connectToServer() { }); client.destroy(); - }) + })) .on('close', () => server.close()); } diff --git a/test/js/node/test/parallel/test-net-sync-cork.js b/test/js/node/test/parallel/test-net-sync-cork.js index 447f42ca91e7..49f68960ce63 100644 --- a/test/js/node/test/parallel/test-net-sync-cork.js +++ b/test/js/node/test/parallel/test-net-sync-cork.js @@ -9,10 +9,10 @@ const server = net.createServer(handle); const N = 100; const buf = Buffer.alloc(2, 'a'); -server.listen(0, function() { +server.listen(0, common.mustCall(function() { const conn = net.connect(this.address().port); - conn.on('connect', () => { + conn.on('connect', common.mustCall(() => { let res = true; let i = 0; for (; i < N && res; i++) { @@ -23,8 +23,8 @@ server.listen(0, function() { } assert.strictEqual(i, N); conn.end(); - }); -}); + })); +})); function handle(socket) { socket.resume(); diff --git a/test/js/node/test/parallel/test-next-tick-errors.js b/test/js/node/test/parallel/test-next-tick-errors.js index 6fd079625afa..28df53c8bfc2 100644 --- a/test/js/node/test/parallel/test-next-tick-errors.js +++ b/test/js/node/test/parallel/test-next-tick-errors.js @@ -20,7 +20,7 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const order = []; @@ -57,7 +57,7 @@ testNextTickWith('str'); testNextTickWith({}); testNextTickWith([]); -process.on('uncaughtException', function(err, errorOrigin) { +process.on('uncaughtException', common.mustCall((err, errorOrigin) => { assert.strictEqual(errorOrigin, 'uncaughtException'); if (!exceptionHandled) { @@ -67,7 +67,7 @@ process.on('uncaughtException', function(err, errorOrigin) { // If we get here then the first process.nextTick got called twice order.push('OOPS!'); } -}); +})); process.on('exit', function() { assert.deepStrictEqual(order, ['A', 'B', 'C']); diff --git a/test/js/node/test/parallel/test-next-tick-fixed-queue-regression.js b/test/js/node/test/parallel/test-next-tick-fixed-queue-regression.js index 1fe82d02b109..82e04e371a72 100644 --- a/test/js/node/test/parallel/test-next-tick-fixed-queue-regression.js +++ b/test/js/node/test/parallel/test-next-tick-fixed-queue-regression.js @@ -14,5 +14,5 @@ process.nextTick(() => { process.nextTick(common.mustCall()); const immediate = setImmediate(common.mustNotCall()); process.nextTick(common.mustCall(() => clearImmediate(immediate))); - }); + }).then(common.mustCall()); }); diff --git a/test/js/node/test/parallel/test-url-format-whatwg.js b/test/js/node/test/parallel/test-url-format-whatwg.js index bf9f8eaac632..12594335d6bd 100644 --- a/test/js/node/test/parallel/test-url-format-whatwg.js +++ b/test/js/node/test/parallel/test-url-format-whatwg.js @@ -1,147 +1,157 @@ 'use strict'; -const common = require('../common'); -if (!common.hasIntl) - common.skip('missing Intl'); +const { hasIntl } = require('../common'); -const assert = require('assert'); -const url = require('url'); +const assert = require('node:assert'); +const url = require('node:url'); +const { test } = require('node:test'); const myURL = new URL('http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c'); -assert.strictEqual( - url.format(myURL), - 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c' -); +test('should format', { skip: !hasIntl }, () => { + assert.strictEqual( + url.format(myURL), + 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c' + ); -assert.strictEqual( - url.format(myURL, {}), - 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c' -); + assert.strictEqual( + url.format(myURL, {}), + 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c' + ); +}); -{ - [true, 1, 'test', Infinity].forEach((value) => { +test('handle invalid arguments', { skip: !hasIntl }, () => { + for (const value of [true, 1, 'test', Infinity]) { assert.throws( () => url.format(myURL, value), { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', - message: 'The "options" argument must be of type object.' + - common.invalidArgTypeHelper(value) } ); - }); -} - -// Any falsy value other than undefined will be treated as false. -// Any truthy value will be treated as true. - -assert.strictEqual( - url.format(myURL, { auth: false }), - 'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c' -); - -assert.strictEqual( - url.format(myURL, { auth: '' }), - 'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c' -); - -assert.strictEqual( - url.format(myURL, { auth: 0 }), - 'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c' -); - -assert.strictEqual( - url.format(myURL, { auth: 1 }), - 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c' -); - -assert.strictEqual( - url.format(myURL, { auth: {} }), - 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c' -); - -assert.strictEqual( - url.format(myURL, { fragment: false }), - 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b' -); - -assert.strictEqual( - url.format(myURL, { fragment: '' }), - 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b' -); - -assert.strictEqual( - url.format(myURL, { fragment: 0 }), - 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b' -); - -assert.strictEqual( - url.format(myURL, { fragment: 1 }), - 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c' -); - -assert.strictEqual( - url.format(myURL, { fragment: {} }), - 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c' -); - -assert.strictEqual( - url.format(myURL, { search: false }), - 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a#c' -); - -assert.strictEqual( - url.format(myURL, { search: '' }), - 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a#c' -); - -assert.strictEqual( - url.format(myURL, { search: 0 }), - 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a#c' -); - -assert.strictEqual( - url.format(myURL, { search: 1 }), - 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c' -); - -assert.strictEqual( - url.format(myURL, { search: {} }), - 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c' -); - -assert.strictEqual( - url.format(myURL, { unicode: true }), - 'http://user:pass@理容ナカムラ.com/a?a=b#c' -); - -assert.strictEqual( - url.format(myURL, { unicode: 1 }), - 'http://user:pass@理容ナカムラ.com/a?a=b#c' -); - -assert.strictEqual( - url.format(myURL, { unicode: {} }), - 'http://user:pass@理容ナカムラ.com/a?a=b#c' -); - -assert.strictEqual( - url.format(myURL, { unicode: false }), - 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c' -); - -assert.strictEqual( - url.format(myURL, { unicode: 0 }), - 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c' -); - -assert.strictEqual( - url.format(new URL('http://user:pass@xn--0zwm56d.com:8080/path'), { unicode: true }), - 'http://user:pass@测试.com:8080/path' -); - -assert.strictEqual( - url.format(new URL('tel:123')), - url.format(new URL('tel:123'), { unicode: true }) -); + } +}); + +test('any falsy value other than undefined will be treated as false', { skip: !hasIntl }, () => { + assert.strictEqual( + url.format(myURL, { auth: false }), + 'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c' + ); + + assert.strictEqual( + url.format(myURL, { auth: '' }), + 'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c' + ); + + assert.strictEqual( + url.format(myURL, { auth: 0 }), + 'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c' + ); + + assert.strictEqual( + url.format(myURL, { auth: 1 }), + 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c' + ); + + assert.strictEqual( + url.format(myURL, { auth: {} }), + 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c' + ); + + assert.strictEqual( + url.format(myURL, { fragment: false }), + 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b' + ); + + assert.strictEqual( + url.format(myURL, { fragment: '' }), + 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b' + ); + + assert.strictEqual( + url.format(myURL, { fragment: 0 }), + 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b' + ); + + assert.strictEqual( + url.format(myURL, { fragment: 1 }), + 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c' + ); + + assert.strictEqual( + url.format(myURL, { fragment: {} }), + 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c' + ); + + assert.strictEqual( + url.format(myURL, { search: false }), + 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a#c' + ); + + assert.strictEqual( + url.format(myURL, { search: '' }), + 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a#c' + ); + + assert.strictEqual( + url.format(myURL, { search: 0 }), + 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a#c' + ); + + assert.strictEqual( + url.format(myURL, { search: 1 }), + 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c' + ); + + assert.strictEqual( + url.format(myURL, { search: {} }), + 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c' + ); + + assert.strictEqual( + url.format(myURL, { unicode: true }), + 'http://user:pass@理容ナカムラ.com/a?a=b#c' + ); + + assert.strictEqual( + url.format(myURL, { unicode: 1 }), + 'http://user:pass@理容ナカムラ.com/a?a=b#c' + ); + + assert.strictEqual( + url.format(myURL, { unicode: {} }), + 'http://user:pass@理容ナカムラ.com/a?a=b#c' + ); + + assert.strictEqual( + url.format(myURL, { unicode: false }), + 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c' + ); + + assert.strictEqual( + url.format(myURL, { unicode: 0 }), + 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c' + ); +}); + +test('should format with unicode: true', { skip: !hasIntl }, () => { + assert.strictEqual( + url.format(new URL('http://user:pass@xn--0zwm56d.com:8080/path'), { unicode: true }), + 'http://user:pass@测试.com:8080/path' + ); +}); + +test('should format tel: prefix', { skip: !hasIntl }, () => { + assert.strictEqual( + url.format(new URL('tel:123')), + url.format(new URL('tel:123'), { unicode: true }) + ); +}); + +// Regression test: url.format should not crash on URLs that ada::url_aggregator +// can parse but ada::url cannot (e.g. special scheme URLs with opaque paths). +test('should not crash on URLs with invalid IDN hostnames', () => { + const u = new URL('ws:xn-\u022B'); + // doesNotThrow + url.format(u, { fragment: false, unicode: false, auth: false, search: false }); +}); diff --git a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-append.js b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-append.js index 50bc4577a2fc..5d2976a23cad 100644 --- a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-append.js +++ b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-append.js @@ -12,14 +12,14 @@ const assert = require('assert'); }, { code: 'ERR_INVALID_THIS', name: 'TypeError', - message: 'Can only call URLSearchParams.append on instances of URLSearchParams', + message: 'Value of "this" must be of type URLSearchParams' }); assert.throws(() => { params.append('a'); }, { code: 'ERR_MISSING_ARGS', name: 'TypeError', - message: 'Not enough arguments' + message: 'The "name" and "value" arguments must be specified' }); const obj = { diff --git a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-delete.js b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-delete.js index 802e9ba01ba2..e84f10e3f93d 100644 --- a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-delete.js +++ b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-delete.js @@ -12,14 +12,14 @@ const assert = require('assert'); }, { code: 'ERR_INVALID_THIS', name: 'TypeError', - message: 'Can only call URLSearchParams.delete on instances of URLSearchParams', + message: 'Value of "this" must be of type URLSearchParams' }); assert.throws(() => { params.delete(); }, { code: 'ERR_MISSING_ARGS', name: 'TypeError', - message: 'Not enough arguments' + message: 'The "name" argument must be specified' }); const obj = { diff --git a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-entries.js b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-entries.js index f05195bc34de..6e5dabb1a768 100644 --- a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-entries.js +++ b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-entries.js @@ -30,12 +30,12 @@ assert.throws(() => { }, { code: 'ERR_INVALID_THIS', name: 'TypeError', - message: 'Cannot call next() on a non-Iterator object' + message: 'Value of "this" must be of type URLSearchParamsIterator' }); assert.throws(() => { params.entries.call(undefined); }, { code: 'ERR_INVALID_THIS', name: 'TypeError', - message: 'Can only call URLSearchParams.entries on instances of URLSearchParams' + message: 'Value of "this" must be of type URLSearchParams' }); diff --git a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-foreach.js b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-foreach.js index 0702ef446306..0c035161dbea 100644 --- a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-foreach.js +++ b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-foreach.js @@ -12,6 +12,6 @@ const assert = require('assert'); }, { code: 'ERR_INVALID_THIS', name: 'TypeError', - message: 'Can only call URLSearchParams.forEach on instances of URLSearchParams' + message: 'Value of "this" must be of type URLSearchParams' }); } diff --git a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-get.js b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-get.js index d718876c2f8d..4ce16805cece 100644 --- a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-get.js +++ b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-get.js @@ -12,14 +12,14 @@ const assert = require('assert'); }, { code: 'ERR_INVALID_THIS', name: 'TypeError', - message: 'Can only call URLSearchParams.get on instances of URLSearchParams', + message: 'Value of "this" must be of type URLSearchParams' }); assert.throws(() => { params.get(); }, { code: 'ERR_MISSING_ARGS', name: 'TypeError', - message: 'Not enough arguments' + message: 'The "name" argument must be specified' }); const obj = { diff --git a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-getall.js b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-getall.js index 457c9add4f54..d3f271fcc5dc 100644 --- a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-getall.js +++ b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-getall.js @@ -12,14 +12,14 @@ const assert = require('assert'); }, { code: 'ERR_INVALID_THIS', name: 'TypeError', - message: 'Can only call URLSearchParams.getAll on instances of URLSearchParams', + message: 'Value of "this" must be of type URLSearchParams' }); assert.throws(() => { params.getAll(); }, { code: 'ERR_MISSING_ARGS', name: 'TypeError', - message: 'Not enough arguments' + message: 'The "name" argument must be specified' }); const obj = { diff --git a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-has.js b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-has.js index f8940dbdafa7..1963e40057ef 100644 --- a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-has.js +++ b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-has.js @@ -12,14 +12,14 @@ const assert = require('assert'); }, { code: 'ERR_INVALID_THIS', name: 'TypeError', - message: 'Can only call URLSearchParams.has on instances of URLSearchParams', + message: 'Value of "this" must be of type URLSearchParams' }); assert.throws(() => { params.has(); }, { code: 'ERR_MISSING_ARGS', name: 'TypeError', - message: 'Not enough arguments' + message: 'The "name" argument must be specified' }); const obj = { diff --git a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-keys.js b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-keys.js index 0883bb6b819a..b65e71c9a241 100644 --- a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-keys.js +++ b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-keys.js @@ -32,12 +32,12 @@ assert.throws(() => { }, { code: 'ERR_INVALID_THIS', name: 'TypeError', - message: 'Cannot call next() on a non-Iterator object' + message: 'Value of "this" must be of type URLSearchParamsIterator' }); assert.throws(() => { params.keys.call(undefined); }, { code: 'ERR_INVALID_THIS', name: 'TypeError', - message: 'Can only call URLSearchParams.keys on instances of URLSearchParams', + message: 'Value of "this" must be of type URLSearchParams' }); diff --git a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-set.js b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-set.js index a892b2267a8f..106e94d6a249 100644 --- a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-set.js +++ b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-set.js @@ -12,14 +12,14 @@ const assert = require('assert'); }, { code: 'ERR_INVALID_THIS', name: 'TypeError', - message: 'Can only call URLSearchParams.set on instances of URLSearchParams', + message: 'Value of "this" must be of type URLSearchParams' }); assert.throws(() => { params.set('a'); }, { code: 'ERR_MISSING_ARGS', name: 'TypeError', - message: 'Not enough arguments' + message: 'The "name" and "value" arguments must be specified' }); const obj = { diff --git a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-stringifier.js b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-stringifier.js index b9a6ea803890..e46865e8b014 100644 --- a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-stringifier.js +++ b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-stringifier.js @@ -12,7 +12,7 @@ const assert = require('assert'); }, { code: 'ERR_INVALID_THIS', name: 'TypeError', - message: 'Can only call URLSearchParams.toString on instances of URLSearchParams', + message: 'Value of "this" must be of type URLSearchParams' }); } diff --git a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-values.js b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-values.js index 305f2529e0df..9c4bb05d0e58 100644 --- a/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-values.js +++ b/test/js/node/test/parallel/test-whatwg-url-custom-searchparams-values.js @@ -32,12 +32,12 @@ assert.throws(() => { }, { code: 'ERR_INVALID_THIS', name: 'TypeError', - message: 'Cannot call next() on a non-Iterator object' + message: 'Value of "this" must be of type URLSearchParamsIterator' }); assert.throws(() => { params.values.call(undefined); }, { code: 'ERR_INVALID_THIS', name: 'TypeError', - message: 'Can only call URLSearchParams.values on instances of URLSearchParams' + message: 'Value of "this" must be of type URLSearchParams' }); diff --git a/test/js/node/test/parallel/test-whatwg-url-invalidthis.js b/test/js/node/test/parallel/test-whatwg-url-invalidthis.js index 9a721a7fdf24..63a26f741115 100644 --- a/test/js/node/test/parallel/test-whatwg-url-invalidthis.js +++ b/test/js/node/test/parallel/test-whatwg-url-invalidthis.js @@ -11,7 +11,7 @@ const assert = require('assert'); ].forEach((i) => { assert.throws(() => Reflect.apply(URL.prototype[i], [], {}), { name: 'TypeError', - message: /Can only call URL\.[a-zA-Z]+ on instances of URL/ + message: /Value of "this" must be of type URL/ }); }); diff --git a/test/js/node/test/parallel/test-zlib-deflate-constructors.js b/test/js/node/test/parallel/test-zlib-deflate-constructors.js index 4c735c78d000..492048d3d0a1 100644 --- a/test/js/node/test/parallel/test-zlib-deflate-constructors.js +++ b/test/js/node/test/parallel/test-zlib-deflate-constructors.js @@ -1,6 +1,6 @@ 'use strict'; -const common = require('../common'); +require('../common'); const zlib = require('zlib'); const assert = require('assert'); @@ -18,7 +18,8 @@ assert.throws( { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', - message: 'The "options.chunkSize" property must be of type number.' + common.invalidArgTypeHelper('test') + message: 'The "options.chunkSize" property must be of type number. ' + + "Received type string ('test')" } ); @@ -51,7 +52,8 @@ assert.throws( { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', - message: 'The "options.windowBits" property must be of type number.' + common.invalidArgTypeHelper('test') + message: 'The "options.windowBits" property must be of type number. ' + + "Received type string ('test')" } ); @@ -91,7 +93,8 @@ assert.throws( { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', - message: 'The "options.level" property must be of type number.' + common.invalidArgTypeHelper('test') + message: 'The "options.level" property must be of type number. ' + + "Received type string ('test')" } ); @@ -131,7 +134,8 @@ assert.throws( { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', - message: 'The "level" argument must be of type number.' + common.invalidArgTypeHelper('test') + message: 'The "level" argument must be of type number. ' + + "Received type string ('test')" } ); @@ -171,7 +175,8 @@ assert.throws( { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', - message: 'The "options.memLevel" property must be of type number.' + common.invalidArgTypeHelper('test') + message: 'The "options.memLevel" property must be of type number. ' + + "Received type string ('test')" } ); @@ -218,7 +223,8 @@ assert.throws( { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', - message: 'The "options.strategy" property must be of type number.' + common.invalidArgTypeHelper('test') + message: 'The "options.strategy" property must be of type number. ' + + "Received type string ('test')" } ); @@ -258,7 +264,8 @@ assert.throws( { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', - message: 'The "strategy" argument must be of type number.' + common.invalidArgTypeHelper('test') + message: 'The "strategy" argument must be of type number. ' + + "Received type string ('test')" } ); @@ -298,5 +305,8 @@ assert.throws( { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', + message: 'The "options.dictionary" property must be an instance of Buffer' + + ', TypedArray, DataView, or ArrayBuffer. Received type string ' + + "('not a buffer')" } ); diff --git a/test/js/node/test/parallel/test-zlib-not-string-or-buffer.js b/test/js/node/test/parallel/test-zlib-not-string-or-buffer.js index 35e969737f92..a0954a0e1eae 100644 --- a/test/js/node/test/parallel/test-zlib-not-string-or-buffer.js +++ b/test/js/node/test/parallel/test-zlib-not-string-or-buffer.js @@ -22,8 +22,8 @@ const zlib = require('zlib'); { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', - message: 'The "buffer" argument must be of type string, ' + - 'Buffer, TypedArray, DataView, or ArrayBuffer.' + + message: 'The "buffer" argument must be of type string or an instance ' + + 'of Buffer, TypedArray, DataView, or ArrayBuffer.' + common.invalidArgTypeHelper(input) } ); diff --git a/test/js/node/test/parallel/test-zlib-zero-windowBits.js b/test/js/node/test/parallel/test-zlib-zero-windowBits.js index a27fd6734a54..220bbf8a4023 100644 --- a/test/js/node/test/parallel/test-zlib-zero-windowBits.js +++ b/test/js/node/test/parallel/test-zlib-zero-windowBits.js @@ -1,33 +1,30 @@ 'use strict'; require('../common'); -const assert = require('assert'); -const zlib = require('zlib'); +const assert = require('node:assert'); +const zlib = require('node:zlib'); +const { test } = require('node:test'); // windowBits is a special case in zlib. On the compression side, 0 is invalid. // On the decompression side, it indicates that zlib should use the value from // the header of the compressed stream. -{ +test('zlib should support zero windowBits', (t) => { const inflate = zlib.createInflate({ windowBits: 0 }); - assert(inflate instanceof zlib.Inflate); -} + assert.ok(inflate instanceof zlib.Inflate); -{ const gunzip = zlib.createGunzip({ windowBits: 0 }); - assert(gunzip instanceof zlib.Gunzip); -} + assert.ok(gunzip instanceof zlib.Gunzip); -{ const unzip = zlib.createUnzip({ windowBits: 0 }); - assert(unzip instanceof zlib.Unzip); -} + assert.ok(unzip instanceof zlib.Unzip); +}); -{ +test('windowBits should be valid', () => { assert.throws(() => zlib.createGzip({ windowBits: 0 }), { code: 'ERR_OUT_OF_RANGE', name: 'RangeError', message: 'The value of "options.windowBits" is out of range. ' + - 'It must be >= 9 and <= 15. Received 0' + 'It must be >= 9 and <= 15. Received 0' }); -} +});