Add generator for $ERR_* as fake private globals (#13843)

Co-authored-by: Jarred-Sumner <Jarred-Sumner@users.noreply.github.com>
This commit is contained in:
Jarred Sumner
2024-09-10 16:07:22 -07:00
committed by GitHub
parent d7f9346f67
commit 8d7d58606b
11 changed files with 291 additions and 81 deletions

View File

@@ -183,68 +183,166 @@ WTF::String JSValueToStringSafe(JSC::JSGlobalObject* globalObject, JSValue arg)
{
ASSERT(!arg.isEmpty());
if (!arg.isCell())
return arg.toString(globalObject)->getString(globalObject);
return arg.toWTFStringForConsole(globalObject);
auto cell = arg.asCell();
auto jstype = cell->type();
if (jstype == JSC::JSType::StringType) {
return cell->toStringInline(globalObject)->getString(globalObject);
switch (cell->type()) {
case JSC::JSType::StringType: {
return arg.toWTFStringForConsole(globalObject);
}
if (jstype == JSC::JSType::SymbolType) {
case JSC::JSType::SymbolType: {
auto symbol = jsCast<Symbol*>(cell);
auto result = symbol->tryGetDescriptiveString();
if (result.has_value())
return result.value();
return "Symbol"_s;
}
return arg.toString(globalObject)->getString(globalObject);
case JSC::JSType::InternalFunctionType:
case JSC::JSType::JSFunctionType: {
auto& vm = globalObject->vm();
auto catchScope = DECLARE_CATCH_SCOPE(vm);
auto name = JSC::getCalculatedDisplayName(vm, cell->getObject());
if (catchScope.exception()) {
catchScope.clearException();
name = "Function"_s;
}
if (!name.isNull() && name.length() > 0) {
return makeString("[Function: "_s, name, ']');
}
return "Function"_s;
break;
}
default: {
break;
}
}
return arg.toWTFStringForConsole(globalObject);
}
JSC_DEFINE_HOST_FUNCTION(jsFunction_ERR_INVALID_ARG_TYPE, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
namespace Message {
WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, const StringView& arg_name, const StringView& expected_type, JSValue actual_value)
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
EXPECT_ARG_COUNT(3);
auto actual_value_string = JSValueToStringSafe(globalObject, actual_value);
RETURN_IF_EXCEPTION(scope, {});
auto arg_name = callFrame->argument(0);
auto expected_type = callFrame->argument(1);
auto actual_value = callFrame->argument(2);
return Bun__ERR_INVALID_ARG_TYPE(globalObject, JSValue::encode(arg_name), JSValue::encode(expected_type), JSValue::encode(actual_value));
return makeString("The \""_s, arg_name, "\" argument must be of type "_s, expected_type, ". Received: "_s, actual_value_string);
}
WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, const StringView& arg_name, ArgList expected_types, JSValue actual_value)
{
WTF::StringBuilder result;
auto actual_value_string = JSValueToStringSafe(globalObject, actual_value);
RETURN_IF_EXCEPTION(scope, {});
result.append("The \""_s, arg_name, "\" argument must be of type "_s);
unsigned length = expected_types.size();
if (length == 1) {
result.append(expected_types.at(0).toWTFString(globalObject));
} else if (length == 2) {
result.append(expected_types.at(0).toWTFString(globalObject));
result.append(" or "_s);
result.append(expected_types.at(1).toWTFString(globalObject));
} else {
for (unsigned i = 0; i < length - 1; i++) {
if (i > 0)
result.append(", "_s);
JSValue expected_type = expected_types.at(i);
result.append(expected_type.toWTFString(globalObject));
}
result.append(" or "_s);
result.append(expected_types.at(length - 1).toWTFString(globalObject));
}
result.append(". Received: "_s, actual_value_string);
return result.toString();
}
WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, const ZigString* arg_name_string, const ZigString* expected_type_string, JSValue actual_value)
{
auto arg_name = std::span<const LChar>(arg_name_string->ptr, arg_name_string->len);
ASSERT(WTF::charactersAreAllASCII(arg_name));
auto expected_type = std::span<const LChar>(expected_type_string->ptr, expected_type_string->len);
ASSERT(WTF::charactersAreAllASCII(expected_type));
return ERR_INVALID_ARG_TYPE(scope, globalObject, arg_name, expected_type, actual_value);
}
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 = val_arg_name.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
auto expected_type = val_expected_type.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
return ERR_INVALID_ARG_TYPE(scope, globalObject, arg_name, expected_type, val_actual_value);
}
WTF::String ERR_OUT_OF_RANGE(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue val_arg_name, JSValue val_range, JSValue val_input)
{
auto arg_name = val_arg_name.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
auto range = val_range.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
auto input = JSValueToStringSafe(globalObject, val_input);
RETURN_IF_EXCEPTION(scope, {});
return makeString("The value of \""_s, arg_name, "\" is out of range. It must be "_s, range, ". Received: \""_s, input, '"');
}
}
static JSC::JSValue ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue arg0, JSValue arg1, JSValue arg2)
{
if (auto* array = jsDynamicCast<JSC::JSArray*>(arg1)) {
const WTF::String argName = arg0.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
MarkedArgumentBuffer expected_types;
for (unsigned i = 0, length = array->length(); i < length; i++) {
expected_types.append(array->getDirectIndex(globalObject, i));
RETURN_IF_EXCEPTION(scope, {});
}
const auto msg = Bun::Message::ERR_INVALID_ARG_TYPE(scope, globalObject, argName, expected_types, arg2);
return createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, msg);
}
const auto msg = Bun::Message::ERR_INVALID_ARG_TYPE(scope, globalObject, arg0, arg1, arg2);
return createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, msg);
}
extern "C" JSC::EncodedJSValue Bun__ERR_INVALID_ARG_TYPE(JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue val_arg_name, JSC::EncodedJSValue val_expected_type, JSC::EncodedJSValue val_actual_value)
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto arg_name = JSValue::decode(val_arg_name).toWTFString(globalObject);
auto message = Message::ERR_INVALID_ARG_TYPE(scope, globalObject, JSValue::decode(val_arg_name), JSValue::decode(val_expected_type), JSValue::decode(val_actual_value));
RETURN_IF_EXCEPTION(scope, {});
auto expected_type = JSValue::decode(val_expected_type).toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
auto actual_value = JSValueToStringSafe(globalObject, JSValue::decode(val_actual_value));
RETURN_IF_EXCEPTION(scope, {});
auto message = makeString("The \""_s, arg_name, "\" argument must be of type "_s, expected_type, ". Received "_s, actual_value);
return JSValue::encode(createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, message));
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, message));
}
extern "C" JSC::EncodedJSValue Bun__ERR_INVALID_ARG_TYPE_static(JSC::JSGlobalObject* globalObject, const ZigString* val_arg_name, const ZigString* val_expected_type, JSC::EncodedJSValue val_actual_value)
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto arg_name = std::span<const unsigned char>(val_arg_name->ptr, val_arg_name->len);
ASSERT(WTF::charactersAreAllASCII(arg_name));
auto expected_type = std::span<const unsigned char>(val_expected_type->ptr, val_expected_type->len);
ASSERT(WTF::charactersAreAllASCII(expected_type));
auto actual_value = JSValueToStringSafe(globalObject, JSValue::decode(val_actual_value));
WTF::String message = Message::ERR_INVALID_ARG_TYPE(scope, globalObject, val_arg_name, val_expected_type, JSValue::decode(val_actual_value));
RETURN_IF_EXCEPTION(scope, {});
auto message = makeString("The \""_s, arg_name, "\" argument must be of type "_s, expected_type, ". Received "_s, actual_value);
return JSValue::encode(createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, message));
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, message));
}
JSC_DEFINE_HOST_FUNCTION(jsFunction_ERR_OUT_OF_RANGE, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
@@ -254,16 +352,8 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_ERR_OUT_OF_RANGE, (JSC::JSGlobalObject * glo
EXPECT_ARG_COUNT(3);
auto arg_name = callFrame->argument(0).toWTFString(globalObject);
auto message = Message::ERR_OUT_OF_RANGE(scope, globalObject, callFrame->argument(0), callFrame->argument(1), callFrame->argument(2));
RETURN_IF_EXCEPTION(scope, {});
auto range = callFrame->argument(1).toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
auto input = callFrame->argument(2).toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
auto message = makeString("The value of \""_s, arg_name, "\" is out of range. It must be "_s, range, ". Received "_s, input);
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_OUT_OF_RANGE, message));
}
@@ -384,6 +474,19 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_ERR_INVALID_PROTOCOL, (JSC::JSGlobalObject *
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_INVALID_PROTOCOL, message));
}
JSC_DEFINE_HOST_FUNCTION(jsFunction_ERR_INVALID_ARG_TYPE, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
EXPECT_ARG_COUNT(3);
auto arg_name = callFrame->argument(0);
auto expected_type = callFrame->argument(1);
auto actual_value = callFrame->argument(2);
return JSValue::encode(ERR_INVALID_ARG_TYPE(scope, globalObject, arg_name, expected_type, actual_value));
}
} // namespace Bun
JSC::JSValue WebCore::toJS(JSC::JSGlobalObject* globalObject, CommonAbortReason abortReason)
@@ -432,4 +535,52 @@ JSC::JSObject* Bun::createInvalidThisError(JSC::JSGlobalObject* globalObject, JS
JSC::EncodedJSValue Bun::throwError(JSC::JSGlobalObject* globalObject, JSC::ThrowScope& scope, Bun::ErrorCode code, const WTF::String& message)
{
return JSC::JSValue::encode(scope.throwException(globalObject, createError(globalObject, code, message)));
}
}
JSC_DEFINE_HOST_FUNCTION(Bun::jsFunctionMakeErrorWithCode, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
EXPECT_ARG_COUNT(2);
JSC::JSValue codeValue = callFrame->argument(0);
RETURN_IF_EXCEPTION(scope, {});
#if BUN_DEBUG
if (!codeValue.isNumber()) {
JSC::throwTypeError(globalObject, scope, "First argument to $ERR_ must be a number"_s);
return {};
}
#endif
int code = codeValue.toInt32(globalObject);
#if BUN_DEBUG
if (code > Bun::NODE_ERROR_COUNT - 1 || code < 0) {
JSC::throwTypeError(globalObject, scope, "Invalid error code. Use $ERR_* constants"_s);
return {};
}
#endif
Bun::ErrorCode error = static_cast<Bun::ErrorCode>(code);
switch (error) {
case Bun::ErrorCode::ERR_INVALID_ARG_TYPE: {
JSValue arg0 = callFrame->argument(1);
JSValue arg1 = callFrame->argument(2);
JSValue arg2 = callFrame->argument(3);
return JSValue::encode(ERR_INVALID_ARG_TYPE(scope, globalObject, arg0, arg1, arg2));
}
default: {
break;
}
}
auto message = callFrame->argument(1).toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
return JSC::JSValue::encode(createError(globalObject, error, message));
}

View File

@@ -62,5 +62,6 @@ JSC_DECLARE_HOST_FUNCTION(jsFunction_ERR_SERVER_NOT_RUNNING);
JSC_DECLARE_HOST_FUNCTION(jsFunction_ERR_IPC_CHANNEL_CLOSED);
JSC_DECLARE_HOST_FUNCTION(jsFunction_ERR_SOCKET_BAD_TYPE);
JSC_DECLARE_HOST_FUNCTION(jsFunction_ERR_INVALID_PROTOCOL);
JSC_DECLARE_HOST_FUNCTION(jsFunctionMakeErrorWithCode);
}

View File

@@ -3437,6 +3437,7 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm)
GlobalPropertyInfo(builtinNames.processBindingConstantsPrivateName(), this->processBindingConstants(), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
GlobalPropertyInfo(builtinNames.requireMapPrivateName(), this->requireMap(), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | 0),
GlobalPropertyInfo(builtinNames.TextEncoderStreamEncoderPrivateName(), JSTextEncoderStreamEncoderConstructor(), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | 0),
GlobalPropertyInfo(builtinNames.makeErrorWithCodePrivateName(), JSFunction::create(vm, this, 2, String(), jsFunctionMakeErrorWithCode, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
};
addStaticGlobals(staticGlobals, std::size(staticGlobals));

View File

@@ -12,6 +12,7 @@ import fs from "fs";
import { mkdir, writeFile } from "fs/promises";
import { builtinModules } from "node:module";
import path from "path";
import ErrorCode from "../bun.js/bindings/ErrorCode";
import { sliceSourceCode } from "./builtin-parser";
import { createAssertClientJS, createLogClientJS } from "./client-js";
import { getJS2NativeCPP, getJS2NativeZig } from "./generate-js2native";
@@ -432,6 +433,31 @@ writeIfNotChanged(path.join(CODEGEN_DIR, "GeneratedJS2Native.h"), getJS2NativeCP
const js2nativeZigPath = path.join(import.meta.dir, "../bun.js/bindings/GeneratedJS2Native.zig");
writeIfNotChanged(js2nativeZigPath, getJS2NativeZig(js2nativeZigPath));
const generatedDTSPath = path.join(CODEGEN_DIR, "generated.d.ts");
writeIfNotChanged(
generatedDTSPath,
(() => {
let dts = `
// GENERATED TEMP FILE - DO NOT EDIT
`;
for (let i = 0; i < ErrorCode.length; i++) {
const [code, _, name] = ErrorCode[i];
dts += `
/**
* Generate a ${name} error with the \`code\` property set to ${code}.
*
* @param msg The error message
* @param args Additional arguments
*/
declare function $${code}(msg: string, ...args: any[]): ${name};
`;
}
return dts;
})(),
);
mark("Generate Code");
if (!silent) {

View File

@@ -1,4 +1,5 @@
import { LoaderKeys } from "../api/schema";
import NodeErrors from "../bun.js/bindings/ErrorCode.ts";
import { sliceSourceCode } from "./builtin-parser";
import { registerNativeCall } from "./generate-js2native";
@@ -12,6 +13,14 @@ export const replacements: ReplacementRule[] = [
{ from: /\bexport\s*default/g, to: "$exports =" },
];
for (let i = 0; i < NodeErrors.length; i++) {
const [code] = NodeErrors[i];
replacements.push({
from: new RegExp(`\\b\\__intrinsic__${code}\\(`, "g"),
to: `$makeErrorWithCode(${i}, `,
});
}
// These rules are run on the entire file, including within strings.
export const globalReplacements: ReplacementRule[] = [
{

View File

@@ -1,3 +1,4 @@
/// <reference types="../../build/codegen/generated.d.ts" />
// Typedefs for JSC intrinsics. Instead of @, we use $
type TODO = any;
@@ -539,3 +540,9 @@ declare var $Buffer: {
declare interface Error {
code?: string;
}
/**
* -- Error Codes with manual messages
*/
declare function $ERR_INVALID_ARG_TYPE(argName: string, expectedType: string, actualValue: string): TypeError;
declare function $ERR_INVALID_ARG_TYPE(argName: string, expectedTypes: any[], actualValue: string): TypeError;

View File

@@ -82,6 +82,7 @@ using namespace JSC;
macro(encoding) \
macro(end) \
macro(errno) \
macro(makeErrorWithCode) \
macro(errorSteps) \
macro(evaluateCommonJSModule) \
macro(evaluated) \

View File

@@ -258,14 +258,6 @@ var NodeError = getNodeErrorByName("Error");
var NodeTypeError = getNodeErrorByName("TypeError");
var NodeRangeError = getNodeErrorByName("RangeError");
class ERR_INVALID_ARG_TYPE extends NodeTypeError {
constructor(name, type, value) {
super(`The "${name}" argument must be of type ${type}. Received type ${typeof value}`, {
code: "ERR_INVALID_ARG_TYPE",
});
}
}
class ERR_INVALID_ARG_VALUE extends NodeTypeError {
constructor(name, value, reason = "not specified") {
super(`The value "${String(value)}" is invalid for argument '${name}'. Reason: ${reason}`, {
@@ -315,7 +307,7 @@ class AbortError extends Error {
* @returns {asserts value is Function}
*/
function validateFunction(value, name) {
if (typeof value !== "function") throw new ERR_INVALID_ARG_TYPE(name, "Function", value);
if (typeof value !== "function") throw $ERR_INVALID_ARG_TYPE(name, "Function", value);
}
/**
@@ -325,7 +317,7 @@ function validateFunction(value, name) {
*/
function validateAbortSignal(signal, name) {
if (signal !== undefined && (signal === null || typeof signal !== "object" || !("aborted" in signal))) {
throw new ERR_INVALID_ARG_TYPE(name, "AbortSignal", signal);
throw $ERR_INVALID_ARG_TYPE(name, "AbortSignal", signal);
}
}
@@ -339,7 +331,7 @@ function validateAbortSignal(signal, name) {
function validateArray(value, name, minLength = 0) {
// var validateArray = hideStackFrames((value, name, minLength = 0) => {
if (!$isJSArray(value)) {
throw new ERR_INVALID_ARG_TYPE(name, "Array", value);
throw $ERR_INVALID_ARG_TYPE(name, "Array", value);
}
if (value.length < minLength) {
var reason = `must be longer than ${minLength}`;
@@ -354,7 +346,7 @@ function validateArray(value, name, minLength = 0) {
* @returns {asserts value is string}
*/
function validateString(value, name) {
if (typeof value !== "string") throw new ERR_INVALID_ARG_TYPE(name, "string", value);
if (typeof value !== "string") throw $ERR_INVALID_ARG_TYPE(name, "string", value);
}
/**
@@ -364,7 +356,7 @@ function validateString(value, name) {
* @returns {asserts value is boolean}
*/
function validateBoolean(value, name) {
if (typeof value !== "boolean") throw new ERR_INVALID_ARG_TYPE(name, "boolean", value);
if (typeof value !== "boolean") throw $ERR_INVALID_ARG_TYPE(name, "boolean", value);
}
/**
@@ -387,7 +379,7 @@ function validateObject(value, name, options = null) {
(!allowArray && $isJSArray.$call(null, value)) ||
(typeof value !== "object" && (!allowFunction || typeof value !== "function"))
) {
throw new ERR_INVALID_ARG_TYPE(name, "object", value);
throw $ERR_INVALID_ARG_TYPE(name, "object", value);
}
}
@@ -400,7 +392,7 @@ function validateObject(value, name, options = null) {
* @returns {asserts value is number}
*/
function validateInteger(value, name, min = NumberMIN_SAFE_INTEGER, max = NumberMAX_SAFE_INTEGER) {
if (typeof value !== "number") throw new ERR_INVALID_ARG_TYPE(name, "number", value);
if (typeof value !== "number") throw $ERR_INVALID_ARG_TYPE(name, "number", value);
if (!NumberIsInteger(value)) throw new ERR_OUT_OF_RANGE(name, "an integer", value);
if (value < min || value > max) throw new ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);
}
@@ -414,7 +406,7 @@ function validateInteger(value, name, min = NumberMIN_SAFE_INTEGER, max = Number
*/
function validateUint32(value, name, positive = false) {
if (typeof value !== "number") {
throw new ERR_INVALID_ARG_TYPE(name, "number", value);
throw $ERR_INVALID_ARG_TYPE(name, "number", value);
}
if (!NumberIsInteger(value)) {
@@ -2897,7 +2889,7 @@ class Readline {
constructor(stream, options = undefined) {
isWritable ??= require("node:stream").isWritable;
if (!isWritable(stream)) throw new ERR_INVALID_ARG_TYPE("stream", "Writable", stream);
if (!isWritable(stream)) throw $ERR_INVALID_ARG_TYPE("stream", "Writable", stream);
this.#stream = stream;
if (options?.autoCommit != null) {
validateBoolean(options.autoCommit, "options.autoCommit");

View File

@@ -654,11 +654,15 @@ describe("fork", () => {
const invalidModulePath = [0, true, undefined, null, [], {}, () => {}, Symbol("t")];
invalidModulePath.forEach(modulePath => {
it(`Ensure that first argument \`modulePath\` must be provided and be of type string :: ${String(modulePath)}`, () => {
expect(() => fork(modulePath, { env: bunEnv })).toThrow({
code: "ERR_INVALID_ARG_TYPE",
name: "TypeError",
message: `The "modulePath" argument must be of type string,Buffer,URL. Received ${String(modulePath)}`,
});
expect(() => fork(modulePath, { env: bunEnv })).toThrow(
expect.objectContaining({
code: "ERR_INVALID_ARG_TYPE",
name: "TypeError",
message: expect.stringContaining(
`The "modulePath" argument must be of type string, Buffer or URL. Received: `,
),
}),
);
});
});
// This test fails due to a DataCloneError or due to "Unable to deserialize data."
@@ -710,11 +714,13 @@ describe("fork", () => {
it(`Ensure that the third argument should be type of object if provided :: ${String(arg)}`, () => {
expect(() => {
fork(fixtures.path("child-process-echo-options.js"), [], arg);
}).toThrow({
code: "ERR_INVALID_ARG_TYPE",
name: "TypeError",
message: `The "options" argument must be of type object. Received ${String(arg)}`,
});
}).toThrow(
expect.objectContaining({
code: "ERR_INVALID_ARG_TYPE",
name: "TypeError",
message: expect.stringContaining(`The "options" argument must be of type object. Received: `),
}),
);
});
});
});

View File

@@ -69,7 +69,7 @@ describe("spawn()", () => {
it("should disallow invalid filename", () => {
// @ts-ignore
expect(() => spawn(123)).toThrow({
message: 'The "file" argument must be of type string. Received 123',
message: 'The "file" argument must be of type string. Received: 123',
code: "ERR_INVALID_ARG_TYPE",
});
});

View File

@@ -90,9 +90,13 @@ describe("readline.clearScreenDown()", () => {
it("should throw on invalid callback", () => {
// Verify that clearScreenDown() throws on invalid callback.
assert.throws(() => {
expect(() => {
readline.clearScreenDown(writable, null);
}, /ERR_INVALID_ARG_TYPE/);
}).toThrowError(
expect.objectContaining({
code: "ERR_INVALID_ARG_TYPE",
}),
);
});
it("should that clearScreenDown() does not throw on null or undefined stream", done => {
@@ -138,9 +142,13 @@ describe("readline.clearLine()", () => {
it("should throw on an invalid callback", () => {
// Verify that clearLine() throws on invalid callback.
assert.throws(() => {
expect(() => {
readline.clearLine(writable, 0, null);
}, /ERR_INVALID_ARG_TYPE/);
}).toThrowError(
expect.objectContaining({
code: "ERR_INVALID_ARG_TYPE",
}),
);
});
it("should not throw on null or undefined stream", done => {
@@ -188,9 +196,13 @@ describe("readline.moveCursor()", () => {
it("should throw on invalid callback", () => {
// Verify that moveCursor() throws on invalid callback.
assert.throws(() => {
expect(() => {
readline.moveCursor(writable, 1, 1, null);
}, /ERR_INVALID_ARG_TYPE/);
}).toThrowError(
expect.objectContaining({
code: "ERR_INVALID_ARG_TYPE",
}),
);
});
it("should not throw on null or undefined stream", done => {
@@ -281,9 +293,13 @@ describe("readline.cursorTo()", () => {
it("should throw on invalid callback", () => {
// Verify that cursorTo() throws on invalid callback.
assert.throws(() => {
expect(() => {
readline.cursorTo(writable, 1, 1, null);
}, /ERR_INVALID_ARG_TYPE/);
}).toThrowError(
expect.objectContaining({
code: "ERR_INVALID_ARG_TYPE",
}),
);
});
it("should throw if x or y is NaN", () => {