diff options
-rw-r--r-- | src/bun.js/api/server.zig | 2 | ||||
-rw-r--r-- | src/bun.js/api/transpiler.zig | 2 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses.cpp | 120 | ||||
-rw-r--r-- | src/bun.js/bindings/bindings.cpp | 7 | ||||
-rw-r--r-- | src/bun.js/bindings/bindings.zig | 10 | ||||
-rw-r--r-- | src/bun.js/bindings/exports.zig | 2 | ||||
-rw-r--r-- | src/bun.js/bindings/generated_classes.zig | 18 | ||||
-rw-r--r-- | src/bun.js/bindings/headers.h | 5 | ||||
-rw-r--r-- | src/bun.js/bindings/headers.zig | 3 | ||||
-rw-r--r-- | src/bun.js/module_loader.zig | 1 | ||||
-rw-r--r-- | src/bun.js/scripts/generate-classes.ts | 4 | ||||
-rw-r--r-- | src/bun.js/test/jest.classes.ts | 24 | ||||
-rw-r--r-- | src/bun.js/test/jest.zig | 387 | ||||
-rw-r--r-- | src/js_ast.zig | 4 | ||||
-rw-r--r-- | src/napi/napi.zig | 2 | ||||
-rw-r--r-- | test/bun.js/test-test.test.ts | 144 |
16 files changed, 670 insertions, 65 deletions
diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig index 1f47af8a0..866b08e34 100644 --- a/src/bun.js/api/server.zig +++ b/src/bun.js/api/server.zig @@ -3942,7 +3942,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type { _: js.ExceptionRef, ) js.JSObjectRef { var globalThis = ctx.ptr(); - + JSC.markBinding(@src()); if (arguments.len == 0) { const fetch_error = WebCore.Fetch.fetch_error_no_args; return JSPromise.rejectedPromiseValue(globalThis, ZigString.init(fetch_error).toErrorInstance(globalThis)).asRef(); diff --git a/src/bun.js/api/transpiler.zig b/src/bun.js/api/transpiler.zig index c48f1f093..4b6b72565 100644 --- a/src/bun.js/api/transpiler.zig +++ b/src/bun.js/api/transpiler.zig @@ -606,7 +606,7 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo var length_iter = iter; while (length_iter.next()) |value| { if (value.isString()) { - const length = value.getLengthOfArray(globalThis); + const length = @truncate(u32, value.getLengthOfArray(globalThis)); string_count += @as(u32, @boolToInt(length > 0)); total_name_buf_len += length; } diff --git a/src/bun.js/bindings/ZigGeneratedClasses.cpp b/src/bun.js/bindings/ZigGeneratedClasses.cpp index 9acbbb1b1..40ced4888 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses.cpp +++ b/src/bun.js/bindings/ZigGeneratedClasses.cpp @@ -5333,6 +5333,12 @@ JSC_DECLARE_HOST_FUNCTION(ExpectPrototype__toBeCallback); extern "C" EncodedJSValue ExpectPrototype__toBeCloseTo(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); JSC_DECLARE_HOST_FUNCTION(ExpectPrototype__toBeCloseToCallback); +extern "C" EncodedJSValue ExpectPrototype__toBeDefined(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(ExpectPrototype__toBeDefinedCallback); + +extern "C" EncodedJSValue ExpectPrototype__toBeFalsy(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(ExpectPrototype__toBeFalsyCallback); + extern "C" EncodedJSValue ExpectPrototype__toBeGreaterThan(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); JSC_DECLARE_HOST_FUNCTION(ExpectPrototype__toBeGreaterThanCallback); @@ -5348,6 +5354,18 @@ JSC_DECLARE_HOST_FUNCTION(ExpectPrototype__toBeLessThanCallback); extern "C" EncodedJSValue ExpectPrototype__toBeLessThanOrEqual(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); JSC_DECLARE_HOST_FUNCTION(ExpectPrototype__toBeLessThanOrEqualCallback); +extern "C" EncodedJSValue ExpectPrototype__toBeNaN(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(ExpectPrototype__toBeNaNCallback); + +extern "C" EncodedJSValue ExpectPrototype__toBeNull(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(ExpectPrototype__toBeNullCallback); + +extern "C" EncodedJSValue ExpectPrototype__toBeTruthy(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(ExpectPrototype__toBeTruthyCallback); + +extern "C" EncodedJSValue ExpectPrototype__toBeUndefined(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(ExpectPrototype__toBeUndefinedCallback); + extern "C" EncodedJSValue ExpectPrototype__toContain(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); JSC_DECLARE_HOST_FUNCTION(ExpectPrototype__toContainCallback); @@ -5419,11 +5437,17 @@ static const HashTableValue JSExpectPrototypeTableValues[] = { { "resolves"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, ExpectPrototype__resolvesGetterWrap, 0 } }, { "toBe"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toBeCallback, 1 } }, { "toBeCloseTo"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toBeCloseToCallback, 1 } }, + { "toBeDefined"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toBeDefinedCallback, 0 } }, + { "toBeFalsy"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toBeFalsyCallback, 0 } }, { "toBeGreaterThan"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toBeGreaterThanCallback, 1 } }, { "toBeGreaterThanOrEqual"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toBeGreaterThanOrEqualCallback, 1 } }, { "toBeInstanceOf"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toBeInstanceOfCallback, 1 } }, { "toBeLessThan"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toBeLessThanCallback, 1 } }, { "toBeLessThanOrEqual"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toBeLessThanOrEqualCallback, 1 } }, + { "toBeNaN"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toBeNaNCallback, 0 } }, + { "toBeNull"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toBeNullCallback, 0 } }, + { "toBeTruthy"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toBeTruthyCallback, 0 } }, + { "toBeUndefined"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toBeUndefinedCallback, 0 } }, { "toContain"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toContainCallback, 1 } }, { "toContainEqual"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toContainEqualCallback, 1 } }, { "toEqual"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toEqualCallback, 1 } }, @@ -5529,6 +5553,38 @@ JSC_DEFINE_HOST_FUNCTION(ExpectPrototype__toBeCloseToCallback, (JSGlobalObject * return ExpectPrototype__toBeCloseTo(thisObject->wrapped(), lexicalGlobalObject, callFrame); } +JSC_DEFINE_HOST_FUNCTION(ExpectPrototype__toBeDefinedCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + auto& vm = lexicalGlobalObject->vm(); + + JSExpect* thisObject = jsDynamicCast<JSExpect*>(callFrame->thisValue()); + + if (UNLIKELY(!thisObject)) { + auto throwScope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(lexicalGlobalObject, throwScope); + } + + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + return ExpectPrototype__toBeDefined(thisObject->wrapped(), lexicalGlobalObject, callFrame); +} + +JSC_DEFINE_HOST_FUNCTION(ExpectPrototype__toBeFalsyCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + auto& vm = lexicalGlobalObject->vm(); + + JSExpect* thisObject = jsDynamicCast<JSExpect*>(callFrame->thisValue()); + + if (UNLIKELY(!thisObject)) { + auto throwScope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(lexicalGlobalObject, throwScope); + } + + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + return ExpectPrototype__toBeFalsy(thisObject->wrapped(), lexicalGlobalObject, callFrame); +} + JSC_DEFINE_HOST_FUNCTION(ExpectPrototype__toBeGreaterThanCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) { auto& vm = lexicalGlobalObject->vm(); @@ -5609,6 +5665,70 @@ JSC_DEFINE_HOST_FUNCTION(ExpectPrototype__toBeLessThanOrEqualCallback, (JSGlobal return ExpectPrototype__toBeLessThanOrEqual(thisObject->wrapped(), lexicalGlobalObject, callFrame); } +JSC_DEFINE_HOST_FUNCTION(ExpectPrototype__toBeNaNCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + auto& vm = lexicalGlobalObject->vm(); + + JSExpect* thisObject = jsDynamicCast<JSExpect*>(callFrame->thisValue()); + + if (UNLIKELY(!thisObject)) { + auto throwScope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(lexicalGlobalObject, throwScope); + } + + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + return ExpectPrototype__toBeNaN(thisObject->wrapped(), lexicalGlobalObject, callFrame); +} + +JSC_DEFINE_HOST_FUNCTION(ExpectPrototype__toBeNullCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + auto& vm = lexicalGlobalObject->vm(); + + JSExpect* thisObject = jsDynamicCast<JSExpect*>(callFrame->thisValue()); + + if (UNLIKELY(!thisObject)) { + auto throwScope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(lexicalGlobalObject, throwScope); + } + + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + return ExpectPrototype__toBeNull(thisObject->wrapped(), lexicalGlobalObject, callFrame); +} + +JSC_DEFINE_HOST_FUNCTION(ExpectPrototype__toBeTruthyCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + auto& vm = lexicalGlobalObject->vm(); + + JSExpect* thisObject = jsDynamicCast<JSExpect*>(callFrame->thisValue()); + + if (UNLIKELY(!thisObject)) { + auto throwScope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(lexicalGlobalObject, throwScope); + } + + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + return ExpectPrototype__toBeTruthy(thisObject->wrapped(), lexicalGlobalObject, callFrame); +} + +JSC_DEFINE_HOST_FUNCTION(ExpectPrototype__toBeUndefinedCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + auto& vm = lexicalGlobalObject->vm(); + + JSExpect* thisObject = jsDynamicCast<JSExpect*>(callFrame->thisValue()); + + if (UNLIKELY(!thisObject)) { + auto throwScope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(lexicalGlobalObject, throwScope); + } + + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + return ExpectPrototype__toBeUndefined(thisObject->wrapped(), lexicalGlobalObject, callFrame); +} + JSC_DEFINE_HOST_FUNCTION(ExpectPrototype__toContainCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) { auto& vm = lexicalGlobalObject->vm(); diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index 25a1b3fc7..f2ce1d201 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -456,7 +456,7 @@ JSC__JSValue JSC__JSValue__createEmptyObject(JSC__JSGlobalObject* globalObject, JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), initialCapacity)); } -uint32_t JSC__JSValue__getLengthOfArray(JSC__JSValue value, JSC__JSGlobalObject* globalObject) +uint64_t JSC__JSValue__getLengthOfArray(JSC__JSValue value, JSC__JSGlobalObject* globalObject) { JSC::JSValue jsValue = JSC::JSValue::decode(value); JSC::JSObject* object = jsValue.toObject(globalObject); @@ -3161,3 +3161,8 @@ JSC__JSValue JSC__JSValue__fastGet_(JSC__JSValue JSValue0, JSC__JSGlobalObject* return JSValue::encode( value.getObject()->getIfPropertyExists(globalObject, builtinNameMap(globalObject, arg2))); } + +bool JSC__JSValue__toBooleanSlow(JSC__JSValue JSValue0, JSC__JSGlobalObject* globalObject) +{ + return JSValue::decode(JSValue0).toBoolean(globalObject); +} diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index e9e4d5cbf..a43f68772 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -2368,7 +2368,7 @@ pub const JSArrayIterator = struct { return .{ .array = value, .global = global, - .len = value.getLengthOfArray(global), + .len = @truncate(u32, value.getLengthOfArray(global)), }; } @@ -3463,6 +3463,10 @@ pub const JSValue = enum(JSValueReprInt) { return fromPtrAddress(@ptrToInt(addr)); } + pub fn toBooleanSlow(this: JSValue, global: *JSGlobalObject) bool { + return cppFn("toBooleanSlow", .{ this, global }); + } + pub fn toBoolean(this: JSValue) bool { if (isUndefinedOrNull(this)) { return false; @@ -3506,7 +3510,7 @@ pub const JSValue = enum(JSValueReprInt) { return @intCast(u32, @maximum(this.toInt32(), 0)); } - pub fn getLengthOfArray(this: JSValue, globalThis: *JSGlobalObject) u32 { + pub fn getLengthOfArray(this: JSValue, globalThis: *JSGlobalObject) u64 { return cppFn("getLengthOfArray", .{ this, globalThis, @@ -3577,7 +3581,7 @@ pub const JSValue = enum(JSValueReprInt) { return this.asNullableVoid().?; } - pub const Extern = [_][]const u8{ "coerceToInt32", "fastGet_", "getStaticProperty", "createUninitializedUint8Array", "fromInt64NoTruncate", "fromUInt64NoTruncate", "toUInt64NoTruncate", "asPromise", "toInt64", "_then", "put", "makeWithNameAndPrototype", "parseJSON", "symbolKeyFor", "symbolFor", "getSymbolDescription", "createInternalPromise", "asInternalPromise", "asArrayBuffer_", "fromEntries", "createTypeError", "createRangeError", "createObject2", "getIfPropertyExistsImpl", "jsType", "jsonStringify", "kind_", "isTerminationException", "isSameValue", "getLengthOfArray", "toZigString", "createStringArray", "createEmptyObject", "putRecord", "asPromise", "isClass", "getNameProperty", "getClassName", "getErrorsProperty", "toInt32", "toBoolean", "isInt32", "isIterable", "forEach", "isAggregateError", "toError", "toZigException", "isException", "toWTFString", "hasProperty", "getPropertyNames", "getDirect", "putDirect", "getIfExists", "asString", "asObject", "asNumber", "isError", "jsNull", "jsUndefined", "jsTDZValue", "jsBoolean", "jsDoubleNumber", "jsNumberFromDouble", "jsNumberFromChar", "jsNumberFromU16", "jsNumberFromInt64", "isBoolean", "isAnyInt", "isUInt32AsAnyInt", "isInt32AsAnyInt", "isNumber", "isString", "isBigInt", "isHeapBigInt", "isBigInt32", "isSymbol", "isPrimitive", "isGetterSetter", "isCustomGetterSetter", "isObject", "isCell", "asCell", "toString", "toStringOrNull", "toPropertyKey", "toPropertyKeyValue", "toObject", "toString", "getPrototype", "getPropertyByPropertyName", "eqlValue", "eqlCell", "isCallable" }; + pub const Extern = [_][]const u8{ "coerceToInt32", "fastGet_", "getStaticProperty", "createUninitializedUint8Array", "fromInt64NoTruncate", "fromUInt64NoTruncate", "toUInt64NoTruncate", "asPromise", "toInt64", "_then", "put", "makeWithNameAndPrototype", "parseJSON", "symbolKeyFor", "symbolFor", "getSymbolDescription", "createInternalPromise", "asInternalPromise", "asArrayBuffer_", "fromEntries", "createTypeError", "createRangeError", "createObject2", "getIfPropertyExistsImpl", "jsType", "jsonStringify", "kind_", "isTerminationException", "isSameValue", "getLengthOfArray", "toZigString", "createStringArray", "createEmptyObject", "putRecord", "asPromise", "isClass", "getNameProperty", "getClassName", "getErrorsProperty", "toInt32", "toBoolean", "isInt32", "isIterable", "forEach", "isAggregateError", "toError", "toZigException", "isException", "toWTFString", "hasProperty", "getPropertyNames", "getDirect", "putDirect", "getIfExists", "asString", "asObject", "asNumber", "isError", "jsNull", "jsUndefined", "jsTDZValue", "jsBoolean", "jsDoubleNumber", "jsNumberFromDouble", "jsNumberFromChar", "jsNumberFromU16", "jsNumberFromInt64", "isBoolean", "isAnyInt", "isUInt32AsAnyInt", "isInt32AsAnyInt", "isNumber", "isString", "isBigInt", "isHeapBigInt", "isBigInt32", "isSymbol", "isPrimitive", "isGetterSetter", "isCustomGetterSetter", "isObject", "isCell", "asCell", "toString", "toStringOrNull", "toPropertyKey", "toPropertyKeyValue", "toObject", "toString", "getPrototype", "getPropertyByPropertyName", "eqlValue", "eqlCell", "isCallable", "toBooleanSlow" }; }; extern "c" fn Microtask__run(*Microtask, *JSGlobalObject) void; diff --git a/src/bun.js/bindings/exports.zig b/src/bun.js/bindings/exports.zig index 1c0a393ce..efa5ab9ef 100644 --- a/src/bun.js/bindings/exports.zig +++ b/src/bun.js/bindings/exports.zig @@ -1766,7 +1766,7 @@ pub const ZigConsoleClient = struct { } }, .Array => { - const len = value.getLengthOfArray(this.globalThis); + const len = @truncate(u32, value.getLengthOfArray(this.globalThis)); if (len == 0) { writer.writeAll("[]"); return; diff --git a/src/bun.js/bindings/generated_classes.zig b/src/bun.js/bindings/generated_classes.zig index d1d1b8f68..67f56082d 100644 --- a/src/bun.js/bindings/generated_classes.zig +++ b/src/bun.js/bindings/generated_classes.zig @@ -1623,6 +1623,10 @@ pub const JSExpect = struct { @compileLog("Expected Expect.toBe to be a callback"); if (@TypeOf(Expect.toBeCloseTo) != CallbackType) @compileLog("Expected Expect.toBeCloseTo to be a callback"); + if (@TypeOf(Expect.toBeDefined) != CallbackType) + @compileLog("Expected Expect.toBeDefined to be a callback"); + if (@TypeOf(Expect.toBeFalsy) != CallbackType) + @compileLog("Expected Expect.toBeFalsy to be a callback"); if (@TypeOf(Expect.toBeGreaterThan) != CallbackType) @compileLog("Expected Expect.toBeGreaterThan to be a callback"); if (@TypeOf(Expect.toBeGreaterThanOrEqual) != CallbackType) @@ -1633,6 +1637,14 @@ pub const JSExpect = struct { @compileLog("Expected Expect.toBeLessThan to be a callback"); if (@TypeOf(Expect.toBeLessThanOrEqual) != CallbackType) @compileLog("Expected Expect.toBeLessThanOrEqual to be a callback"); + if (@TypeOf(Expect.toBeNaN) != CallbackType) + @compileLog("Expected Expect.toBeNaN to be a callback"); + if (@TypeOf(Expect.toBeNull) != CallbackType) + @compileLog("Expected Expect.toBeNull to be a callback"); + if (@TypeOf(Expect.toBeTruthy) != CallbackType) + @compileLog("Expected Expect.toBeTruthy to be a callback"); + if (@TypeOf(Expect.toBeUndefined) != CallbackType) + @compileLog("Expected Expect.toBeUndefined to be a callback"); if (@TypeOf(Expect.toContain) != CallbackType) @compileLog("Expected Expect.toContain to be a callback"); if (@TypeOf(Expect.toContainEqual) != CallbackType) @@ -1728,11 +1740,17 @@ pub const JSExpect = struct { @export(Expect.stringMatching, .{ .name = "ExpectClass__stringMatching" }); @export(Expect.toBe, .{ .name = "ExpectPrototype__toBe" }); @export(Expect.toBeCloseTo, .{ .name = "ExpectPrototype__toBeCloseTo" }); + @export(Expect.toBeDefined, .{ .name = "ExpectPrototype__toBeDefined" }); + @export(Expect.toBeFalsy, .{ .name = "ExpectPrototype__toBeFalsy" }); @export(Expect.toBeGreaterThan, .{ .name = "ExpectPrototype__toBeGreaterThan" }); @export(Expect.toBeGreaterThanOrEqual, .{ .name = "ExpectPrototype__toBeGreaterThanOrEqual" }); @export(Expect.toBeInstanceOf, .{ .name = "ExpectPrototype__toBeInstanceOf" }); @export(Expect.toBeLessThan, .{ .name = "ExpectPrototype__toBeLessThan" }); @export(Expect.toBeLessThanOrEqual, .{ .name = "ExpectPrototype__toBeLessThanOrEqual" }); + @export(Expect.toBeNaN, .{ .name = "ExpectPrototype__toBeNaN" }); + @export(Expect.toBeNull, .{ .name = "ExpectPrototype__toBeNull" }); + @export(Expect.toBeTruthy, .{ .name = "ExpectPrototype__toBeTruthy" }); + @export(Expect.toBeUndefined, .{ .name = "ExpectPrototype__toBeUndefined" }); @export(Expect.toContain, .{ .name = "ExpectPrototype__toContain" }); @export(Expect.toContainEqual, .{ .name = "ExpectPrototype__toContainEqual" }); @export(Expect.toEqual, .{ .name = "ExpectPrototype__toEqual" }); diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h index a3f71adb3..ffaa896df 100644 --- a/src/bun.js/bindings/headers.h +++ b/src/bun.js/bindings/headers.h @@ -1,5 +1,5 @@ // clang-format off -//-- AUTOGENERATED FILE -- 1667784809 +//-- AUTOGENERATED FILE -- 1668835252 #pragma once #include <stddef.h> @@ -496,7 +496,7 @@ CPP_DECL JSC__JSValue JSC__JSValue__fromUInt64NoTruncate(JSC__JSGlobalObject* ar CPP_DECL void JSC__JSValue__getClassName(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, ZigString* arg2); CPP_DECL JSC__JSValue JSC__JSValue__getErrorsProperty(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1); CPP_DECL JSC__JSValue JSC__JSValue__getIfPropertyExistsImpl(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, const unsigned char* arg2, uint32_t arg3); -CPP_DECL uint32_t JSC__JSValue__getLengthOfArray(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1); +CPP_DECL uint64_t JSC__JSValue__getLengthOfArray(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1); CPP_DECL void JSC__JSValue__getNameProperty(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, ZigString* arg2); CPP_DECL JSC__JSValue JSC__JSValue__getPrototype(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1); CPP_DECL void JSC__JSValue__getSymbolDescription(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, ZigString* arg2); @@ -542,6 +542,7 @@ CPP_DECL void JSC__JSValue__putRecord(JSC__JSValue JSValue0, JSC__JSGlobalObject CPP_DECL JSC__JSValue JSC__JSValue__symbolFor(JSC__JSGlobalObject* arg0, ZigString* arg1); CPP_DECL bool JSC__JSValue__symbolKeyFor(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, ZigString* arg2); CPP_DECL bool JSC__JSValue__toBoolean(JSC__JSValue JSValue0); +CPP_DECL bool JSC__JSValue__toBooleanSlow(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1); CPP_DECL JSC__JSValue JSC__JSValue__toError(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1); CPP_DECL int32_t JSC__JSValue__toInt32(JSC__JSValue JSValue0); CPP_DECL int64_t JSC__JSValue__toInt64(JSC__JSValue JSValue0); diff --git a/src/bun.js/bindings/headers.zig b/src/bun.js/bindings/headers.zig index e0909ba8c..5e7ace610 100644 --- a/src/bun.js/bindings/headers.zig +++ b/src/bun.js/bindings/headers.zig @@ -289,7 +289,7 @@ pub extern fn JSC__JSValue__fromUInt64NoTruncate(arg0: ?*JSC__JSGlobalObject, ar pub extern fn JSC__JSValue__getClassName(JSValue0: JSC__JSValue, arg1: ?*JSC__JSGlobalObject, arg2: [*c]ZigString) void; pub extern fn JSC__JSValue__getErrorsProperty(JSValue0: JSC__JSValue, arg1: ?*JSC__JSGlobalObject) JSC__JSValue; pub extern fn JSC__JSValue__getIfPropertyExistsImpl(JSValue0: JSC__JSValue, arg1: ?*JSC__JSGlobalObject, arg2: [*c]const u8, arg3: u32) JSC__JSValue; -pub extern fn JSC__JSValue__getLengthOfArray(JSValue0: JSC__JSValue, arg1: ?*JSC__JSGlobalObject) u32; +pub extern fn JSC__JSValue__getLengthOfArray(JSValue0: JSC__JSValue, arg1: ?*JSC__JSGlobalObject) u64; pub extern fn JSC__JSValue__getNameProperty(JSValue0: JSC__JSValue, arg1: ?*JSC__JSGlobalObject, arg2: [*c]ZigString) void; pub extern fn JSC__JSValue__getPrototype(JSValue0: JSC__JSValue, arg1: ?*JSC__JSGlobalObject) JSC__JSValue; pub extern fn JSC__JSValue__getSymbolDescription(JSValue0: JSC__JSValue, arg1: ?*JSC__JSGlobalObject, arg2: [*c]ZigString) void; @@ -335,6 +335,7 @@ pub extern fn JSC__JSValue__putRecord(JSValue0: JSC__JSValue, arg1: ?*JSC__JSGlo pub extern fn JSC__JSValue__symbolFor(arg0: ?*JSC__JSGlobalObject, arg1: [*c]ZigString) JSC__JSValue; pub extern fn JSC__JSValue__symbolKeyFor(JSValue0: JSC__JSValue, arg1: ?*JSC__JSGlobalObject, arg2: [*c]ZigString) bool; pub extern fn JSC__JSValue__toBoolean(JSValue0: JSC__JSValue) bool; +pub extern fn JSC__JSValue__toBooleanSlow(JSValue0: JSC__JSValue, arg1: ?*JSC__JSGlobalObject) bool; pub extern fn JSC__JSValue__toError(JSValue0: JSC__JSValue, arg1: ?*JSC__JSGlobalObject) JSC__JSValue; pub extern fn JSC__JSValue__toInt32(JSValue0: JSC__JSValue) i32; pub extern fn JSC__JSValue__toInt64(JSValue0: JSC__JSValue) i64; diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig index 59a4288fb..290f3bf85 100644 --- a/src/bun.js/module_loader.zig +++ b/src/bun.js/module_loader.zig @@ -547,6 +547,7 @@ pub const ModuleLoader = struct { } pub fn onDone(this: *AsyncModule) void { + JSC.markBinding(@src()); var jsc_vm = this.globalThis.bunVM(); jsc_vm.modules.scheduled -= 1; if (jsc_vm.modules.scheduled == 0) { diff --git a/src/bun.js/scripts/generate-classes.ts b/src/bun.js/scripts/generate-classes.ts index 6689667b2..aa0eab9d8 100644 --- a/src/bun.js/scripts/generate-classes.ts +++ b/src/bun.js/scripts/generate-classes.ts @@ -823,7 +823,7 @@ JSC_DEFINE_CUSTOM_GETTER(${symbolName( typeName, proto[name].getter, )}(thisObject->wrapped(),${ - proto[name].this!! ? " thisValue, " : "" + !!proto[name].this ? " thisValue, " : "" } globalObject); RETURN_IF_EXCEPTION(throwScope, {}); RELEASE_AND_RETURN(throwScope, result); @@ -852,7 +852,7 @@ JSC_DEFINE_CUSTOM_SETTER(${symbolName( typeName, proto[name].setter || proto[name].accessor.setter, )}(thisObject->wrapped(),${ - proto[name].this!! ? " thisValue, " : "" + !!proto[name].this ? " thisValue, " : "" } lexicalGlobalObject, encodedValue); RELEASE_AND_RETURN(throwScope, result); diff --git a/src/bun.js/test/jest.classes.ts b/src/bun.js/test/jest.classes.ts index d1d225f64..ad2a5d6e8 100644 --- a/src/bun.js/test/jest.classes.ts +++ b/src/bun.js/test/jest.classes.ts @@ -128,6 +128,30 @@ export default [ fn: "toBeInstanceOf", length: 1, }, + toBeTruthy: { + fn: "toBeTruthy", + length: 0, + }, + toBeUndefined: { + fn: "toBeUndefined", + length: 0, + }, + toBeNaN: { + fn: "toBeNaN", + length: 0, + }, + toBeNull: { + fn: "toBeNull", + length: 0, + }, + toBeFalsy: { + fn: "toBeFalsy", + length: 0, + }, + toBeDefined: { + fn: "toBeDefined", + length: 0, + }, toContain: { fn: "toContain", length: 1, diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig index 4d67ea97f..3439e46a4 100644 --- a/src/bun.js/test/jest.zig +++ b/src/bun.js/test/jest.zig @@ -37,6 +37,7 @@ const JSPromise = JSC.JSPromise; const JSValue = JSC.JSValue; const JSError = JSC.JSError; const JSGlobalObject = JSC.JSGlobalObject; +const JSObject = JSC.JSObject; const VirtualMachine = @import("../javascript.zig").VirtualMachine; const Task = @import("../javascript.zig").Task; @@ -315,31 +316,29 @@ pub const Expect = struct { return .zero; }; right.ensureStillAlive(); - const eql = left.isSameValue(right, globalObject); + + const not = this.op.contains(.not); + var pass = left.isSameValue(right, globalObject); if (comptime Environment.allow_assert) { - std.debug.assert(eql == JSC.C.JSValueIsStrictEqual(globalObject, left.asObjectRef(), right.asObjectRef())); + std.debug.assert(pass == JSC.C.JSValueIsStrictEqual(globalObject, left.asObjectRef(), right.asObjectRef())); } - if (!eql) { - var lhs_formatter: JSC.ZigConsoleClient.Formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject }; - var rhs_formatter: JSC.ZigConsoleClient.Formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject }; - - if (comptime Environment.allow_assert) { - Output.prettyErrorln("\nJSType: {s}\nJSType: {s}\n\n", .{ @tagName(left.jsType()), @tagName(right.jsType()) }); - } - - globalObject.throw( - "Expected: {any}\n\tReceived: {any}", - .{ - left.toFmt(globalObject, &lhs_formatter), - right.toFmt(globalObject, &rhs_formatter), - }, - ); + if (not) pass = !pass; + if (pass) return thisValue; - return .zero; + // handle failure + var lhs_fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject }; + var rhs_fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject }; + if (comptime Environment.allow_assert) { + Output.prettyErrorln("\nJSType: {s}\nJSType: {s}\n\n", .{ @tagName(left.jsType()), @tagName(right.jsType()) }); } - return thisValue; + if (not) { + globalObject.throw("\n\tExpected: not {any}\n\tReceived: {any}", .{ left.toFmt(globalObject, &lhs_fmt), right.toFmt(globalObject, &rhs_fmt) }); + } else { + globalObject.throw("\n\tExpected: {any}\n\tReceived: {any}", .{ left.toFmt(globalObject, &lhs_fmt), right.toFmt(globalObject, &rhs_fmt) }); + } + return .zero; } pub fn toHaveLength( @@ -363,25 +362,304 @@ pub const Expect = struct { active_test_expectation_counter.actual += 1; - const expected = arguments[0].coerce(i32, globalObject); - const value = JSC.Jest.Expect.capturedValueGetCached(thisValue) orelse { + const expected: JSValue = arguments[0]; + const value: JSValue = JSC.Jest.Expect.capturedValueGetCached(thisValue) orelse { globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{}); return .zero; }; - const actual = value.getLengthOfArray(globalObject); - if (expected != actual) { - globalObject.throw("Expected length to equal {d} but received {d}\n Expected: {d}\n Actual: {d}\n", .{ - expected, - actual, - expected, - actual, - }); + value.ensureStillAlive(); + + if (!value.isObject() and !value.isString()) { + var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject }; + globalObject.throw("Received value does not have a length property: {any}", .{value.toFmt(globalObject, &fmt)}); return .zero; } - return thisValue; + if (!expected.isNumber()) { + var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject }; + globalObject.throw("Expected value must be a non-negative integer: {any}", .{expected.toFmt(globalObject, &fmt)}); + return .zero; + } + + const expected_length: f64 = expected.asNumber(); + if (@round(expected_length) != expected_length or std.math.isInf(expected_length) or std.math.isNan(expected_length) or expected_length < 0) { + var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject }; + globalObject.throw("Expected value must be a non-negative integer: {any}", .{expected.toFmt(globalObject, &fmt)}); + return .zero; + } + + const not = this.op.contains(.not); + var pass = false; + + var actual_length: f64 = undefined; + if (value.isString()) { + actual_length = @intToFloat(f64, value.asString().length()); + if (actual_length == expected_length) pass = true; + } else { + const length_value: JSValue = value.getIfPropertyExistsImpl(globalObject, "length", "length".len); + + if (length_value.isEmpty()) { + var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject }; + globalObject.throw("Received value does not have a length property: {any}", .{value.toFmt(globalObject, &fmt)}); + return .zero; + } else if (!length_value.isNumber()) { + var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject }; + globalObject.throw("Received value has non-number length property: {any}", .{length_value.toFmt(globalObject, &fmt)}); + return .zero; + } + + actual_length = length_value.asNumber(); + if (@round(actual_length) == actual_length) { + if (actual_length == expected_length) pass = true; + } + } + + if (not) pass = !pass; + if (pass) return thisValue; + + // handle failure + if (not) { + globalObject.throw("\n\tExpected: not {d}\n\tReceived: {d}", .{ expected_length, actual_length }); + } else { + globalObject.throw("\n\tExpected: {d}\n\tReceived: {d}", .{ expected_length, actual_length }); + } + return .zero; + } + + pub fn toContain( + this: *Expect, + globalObject: *JSC.JSGlobalObject, + callFrame: *JSC.CallFrame, + ) callconv(.C) JSC.JSValue { + const thisValue = callFrame.this(); + const arguments_ = callFrame.arguments(1); + const arguments = arguments_.ptr[0..arguments_.len]; + + if (arguments.len < 1) { + globalObject.throwInvalidArguments("toContain() takes 1 argument", .{}); + return .zero; + } + + if (this.scope.tests.items.len <= this.test_id) { + globalObject.throw("toContain() must be called in a test", .{}); + return .zero; + } + + active_test_expectation_counter.actual += 1; + + const expected = arguments[0]; + expected.ensureStillAlive(); + const value: JSValue = JSC.Jest.Expect.capturedValueGetCached(thisValue) orelse { + globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{}); + return .zero; + }; + value.ensureStillAlive(); + + const not = this.op.contains(.not); + var pass = false; + + if (value.isIterable(globalObject)) { + var itr = value.arrayIterator(globalObject); + while (itr.next()) |item| { + if (item.isSameValue(expected, globalObject)) { + pass = true; + break; + } + } + } else if (value.isString() and expected.isString()) { + const value_string = value.toString(globalObject).toSlice(globalObject, default_allocator).slice(); + const expected_string = expected.toString(globalObject).toSlice(globalObject, default_allocator).slice(); + if (strings.contains(value_string, expected_string)) { + pass = true; + } + } else { + globalObject.throw("Received value must be an array type, or both received and expected values must be strings.", .{}); + return .zero; + } + + if (not) pass = !pass; + if (pass) return thisValue; + + // handle failure + var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject }; + if (not) { + globalObject.throw("Expected to not contain \"{any}\"", .{expected.toFmt(globalObject, &fmt)}); + } else { + globalObject.throw("Expected to contain \"{any}\"", .{expected.toFmt(globalObject, &fmt)}); + } + return .zero; } + pub fn toBeTruthy(this: *Expect, globalObject: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSC.JSValue { + const thisValue = callFrame.this(); + const value: JSValue = Expect.capturedValueGetCached(thisValue) orelse { + globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{}); + return .zero; + }; + value.ensureStillAlive(); + + if (this.scope.tests.items.len <= this.test_id) { + globalObject.throw("toBeTruthy() must be called in a test", .{}); + return .zero; + } + + active_test_expectation_counter.actual += 1; + + const not = this.op.contains(.not); + var pass = false; + + const truthy = value.toBooleanSlow(globalObject); + if (truthy) pass = true; + + if (not) pass = !pass; + if (pass) return thisValue; + + // handle failure + var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject }; + if (not) { + globalObject.throw("Expected \"{any}\" to be not truthy.", .{value.toFmt(globalObject, &fmt)}); + } else { + globalObject.throw("Expected \"{any}\" to be truthy.", .{value.toFmt(globalObject, &fmt)}); + } + return .zero; + } + + pub fn toBeUndefined(this: *Expect, globalObject: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSC.JSValue { + const thisValue = callFrame.this(); + const value: JSValue = Expect.capturedValueGetCached(thisValue) orelse { + globalObject.throw("Interal consistency error: the expect(value) was garbage collected but it should not have been!", .{}); + return .zero; + }; + value.ensureStillAlive(); + + active_test_expectation_counter.actual += 1; + + const not = this.op.contains(.not); + var pass = false; + if (value.isUndefined()) pass = true; + + if (not) pass = !pass; + if (pass) return thisValue; + + // handle failure + var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject }; + if (not) { + globalObject.throw("Expected \"{any}\" to be not undefined.", .{value.toFmt(globalObject, &fmt)}); + } else { + globalObject.throw("Expected \"{any}\" to be undefined.", .{value.toFmt(globalObject, &fmt)}); + } + return .zero; + } + + pub fn toBeNaN(this: *Expect, globalObject: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSC.JSValue { + const thisValue = callFrame.this(); + const value: JSValue = Expect.capturedValueGetCached(thisValue) orelse { + globalObject.throw("Interal consistency error: the expect(value) was garbage collected but it should not have been!", .{}); + return .zero; + }; + value.ensureStillAlive(); + + active_test_expectation_counter.actual += 1; + + const not = this.op.contains(.not); + var pass = false; + if (value.isNumber()) { + const number = value.asNumber(); + if (number != number) pass = true; + } + + if (not) pass = !pass; + if (pass) return thisValue; + + // handle failure + var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject }; + if (not) { + globalObject.throw("Expected \"{any}\" to be not NaN.", .{value.toFmt(globalObject, &fmt)}); + } else { + globalObject.throw("Expected \"{any}\" to be NaN.", .{value.toFmt(globalObject, &fmt)}); + } + return .zero; + } + + pub fn toBeNull(this: *Expect, globalObject: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSC.JSValue { + const thisValue = callFrame.this(); + const value: JSValue = Expect.capturedValueGetCached(thisValue) orelse { + globalObject.throw("Interal consistency error: the expect(value) was garbage collected but it should not have been!", .{}); + return .zero; + }; + value.ensureStillAlive(); + + active_test_expectation_counter.actual += 1; + + const not = this.op.contains(.not); + var pass = value.isNull(); + if (not) pass = !pass; + if (pass) return thisValue; + + // handle failure + var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject }; + if (not) { + globalObject.throw("Expected \"{any}\" to be not null.", .{value.toFmt(globalObject, &fmt)}); + } else { + globalObject.throw("Expected \"{any}\" to be null.", .{value.toFmt(globalObject, &fmt)}); + } + return .zero; + } + + pub fn toBeDefined(this: *Expect, globalObject: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSC.JSValue { + const thisValue = callFrame.this(); + const value: JSValue = Expect.capturedValueGetCached(thisValue) orelse { + globalObject.throw("Interal consistency error: the expect(value) was garbage collected but it should not have been!", .{}); + return .zero; + }; + value.ensureStillAlive(); + + active_test_expectation_counter.actual += 1; + + const not = this.op.contains(.not); + var pass = !value.isUndefined(); + if (not) pass = !pass; + if (pass) return thisValue; + + // handle failure + var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject }; + if (not) { + globalObject.throw("Expected \"{any}\" to be not defined.", .{value.toFmt(globalObject, &fmt)}); + } else { + globalObject.throw("Expected \"{any}\" to be defined.", .{value.toFmt(globalObject, &fmt)}); + } + return .zero; + } + + pub fn toBeFalsy(this: *Expect, globalObject: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSC.JSValue { + const thisValue = callFrame.this(); + + const value: JSValue = Expect.capturedValueGetCached(thisValue) orelse { + globalObject.throw("internal consistency error: the expect(value) was garbage collected but it should not have been!", .{}); + return .zero; + }; + value.ensureStillAlive(); + + const not = this.op.contains(.not); + var pass = false; + + const truthy = value.toBooleanSlow(globalObject); + if (!truthy) pass = true; + + if (not) pass = !pass; + if (pass) return thisValue; + + // handle failure + var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject }; + if (not) { + globalObject.throw("Expected \"{any}\" to be not falsy.", .{value.toFmt(globalObject, &fmt)}); + } else { + globalObject.throw("Expected \"{any}\" to be falsy.", .{value.toFmt(globalObject, &fmt)}); + } + return .zero; + } + + pub const toHaveProperty = notImplementedJSCFn; pub const toHaveBeenCalledTimes = notImplementedJSCFn; pub const toHaveBeenCalledWith = notImplementedJSCFn; pub const toHaveBeenLastCalledWith = notImplementedJSCFn; @@ -390,14 +668,12 @@ pub const Expect = struct { pub const toHaveReturnedWith = notImplementedJSCFn; pub const toHaveLastReturnedWith = notImplementedJSCFn; pub const toHaveNthReturnedWith = notImplementedJSCFn; - pub const toHaveProperty = notImplementedJSCFn; pub const toBeCloseTo = notImplementedJSCFn; pub const toBeGreaterThan = notImplementedJSCFn; pub const toBeGreaterThanOrEqual = notImplementedJSCFn; pub const toBeLessThan = notImplementedJSCFn; pub const toBeLessThanOrEqual = notImplementedJSCFn; pub const toBeInstanceOf = notImplementedJSCFn; - pub const toContain = notImplementedJSCFn; pub const toContainEqual = notImplementedJSCFn; pub const toEqual = notImplementedJSCFn; pub const toMatch = notImplementedJSCFn; @@ -409,6 +685,35 @@ pub const Expect = struct { pub const toThrowErrorMatchingSnapshot = notImplementedJSCFn; pub const toThrowErrorMatchingInlineSnapshot = notImplementedJSCFn; + pub const getStaticNot = notImplementedStaticProp; + pub const getStaticResolves = notImplementedStaticProp; + pub const getStaticRejects = notImplementedStaticProp; + + pub fn getNot(this: *Expect, thisValue: JSValue, globalObject: *JSGlobalObject) callconv(.C) JSValue { + _ = Expect.capturedValueGetCached(thisValue) orelse { + globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{}); + return .zero; + }; + + this.op.toggle(.not); + + return thisValue; + } + + pub const getResolves = notImplementedJSCProp; + pub const getRejects = notImplementedJSCProp; + + pub const extend = notImplementedStaticFn; + pub const anything = notImplementedStaticFn; + pub const any = notImplementedStaticFn; + pub const arrayContaining = notImplementedStaticFn; + pub const assertions = notImplementedStaticFn; + pub const hasAssertions = notImplementedStaticFn; + pub const objectContaining = notImplementedStaticFn; + pub const stringContaining = notImplementedStaticFn; + pub const stringMatching = notImplementedStaticFn; + pub const addSnapshotSerializer = notImplementedStaticFn; + pub fn notImplementedJSCFn(_: *Expect, globalObject: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSC.JSValue { globalObject.throw("Not implemented", .{}); return .zero; @@ -428,24 +733,6 @@ pub const Expect = struct { globalObject.throw("Not implemented", .{}); return .zero; } - - pub const getStaticNot = notImplementedStaticProp; - pub const getStaticResolves = notImplementedStaticProp; - pub const getStaticRejects = notImplementedStaticProp; - pub const getNot = notImplementedJSCProp; - pub const getResolves = notImplementedJSCProp; - pub const getRejects = notImplementedJSCProp; - - pub const extend = notImplementedStaticFn; - pub const anything = notImplementedStaticFn; - pub const any = notImplementedStaticFn; - pub const arrayContaining = notImplementedStaticFn; - pub const assertions = notImplementedStaticFn; - pub const hasAssertions = notImplementedStaticFn; - pub const objectContaining = notImplementedStaticFn; - pub const stringContaining = notImplementedStaticFn; - pub const stringMatching = notImplementedStaticFn; - pub const addSnapshotSerializer = notImplementedStaticFn; }; pub const TestScope = struct { diff --git a/src/js_ast.zig b/src/js_ast.zig index 0bd73c93f..0ca11272a 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -7128,7 +7128,7 @@ pub const Macro = struct { while (i < count) { var nextArg = writer.eatArg() orelse return false; if (js.JSValueIsArray(writer.ctx, nextArg.asRef())) { - const extras = nextArg.getLengthOfArray(writer.ctx.ptr()); + const extras = @truncate(u32, nextArg.getLengthOfArray(writer.ctx.ptr())); count += std.math.max(@truncate(@TypeOf(count), extras), 1) - 1; items.ensureUnusedCapacity(extras) catch unreachable; items.expandToCapacity(); @@ -7511,7 +7511,7 @@ pub const Macro = struct { .allocator = JSCBase.getAllocator(ctx), .exception = exception, .args_value = args_value, - .args_len = args_value.getLengthOfArray(ctx.ptr()), + .args_len = @truncate(u32, args_value.getLengthOfArray(ctx.ptr())), .args_i = 0, .errored = false, }; diff --git a/src/napi/napi.zig b/src/napi/napi.zig index c30f1d565..260e5ba22 100644 --- a/src/napi/napi.zig +++ b/src/napi/napi.zig @@ -604,7 +604,7 @@ pub export fn napi_get_array_length(env: napi_env, value: napi_value, result: [* return .array_expected; } - result.* = value.getLengthOfArray(env); + result.* = @truncate(u32, value.getLengthOfArray(env)); return .ok; } pub export fn napi_strict_equals(env: napi_env, lhs: napi_value, rhs: napi_value, result: *bool) napi_status { diff --git a/test/bun.js/test-test.test.ts b/test/bun.js/test-test.test.ts new file mode 100644 index 000000000..8ada29ed0 --- /dev/null +++ b/test/bun.js/test-test.test.ts @@ -0,0 +1,144 @@ +import { expect, test } from "@jest/globals"; + +test("toBe()", () => { + const a = 1; + const b = 1; + expect(a).toBe(a); + expect(a).toBe(b); + expect(a).toBe(1); + expect(1).toBe(a); + expect(b).toBe(a); + + const c = { a: 1 }; + const d = { a: 1 }; + expect(c).toBe(c); + expect(c).not.toBe(d); + expect(c).not.toBe({ a: 1 }); + expect({ a: 1 }).not.toBe(c); + expect(d).not.toBe(c); + + expect(1).toBe(1); + // expect(1).not.toBe(1); + + expect(1).not.toBe(2); + expect(1).not.toBe("1"); + expect("hello test").toBe("hello test"); + expect("hello test").not.toBe("hello test2"); +}); + +test("toHaveLength()", () => { + expect({ length: Number.MAX_SAFE_INTEGER }).toHaveLength( + Number.MAX_SAFE_INTEGER, + ); + expect("123").toHaveLength(3); + expect([1, 2, 3]).toHaveLength(3); + expect([1, 2, 3]).not.toHaveLength(2); + expect("123").not.toHaveLength(2); + expect({ length: 3 }).toHaveLength(3); + expect({ length: 3 }).not.toHaveLength(2); + expect({ length: 3 }).not.toHaveLength(Number.MAX_SAFE_INTEGER); + expect({ length: Number.MAX_SAFE_INTEGER }).not.toHaveLength( + Number.MAX_SAFE_INTEGER - 1, + ); + expect({ length: 3.3 }).not.toHaveLength(3); + expect("123").not.toHaveLength(-0); +}); + +test("toContain()", () => { + const s1 = new String("123"); + expect(s1).not.toContain("12"); + const s2 = "123"; + expect(s2).toContain("12"); + + expect("test").toContain("es"); + expect("test").toContain("est"); + expect("test").toContain("test"); + expect(["test", "es"]).toContain("es"); + expect("").toContain(""); + expect([""]).toContain(""); + + expect(["lemon", "lime"]).not.toContain("orange"); + expect("citrus fruits").toContain("fruit"); + + const a = new Uint16Array([1, 2, 3]); + expect(a).toContain(2); + expect(a).not.toContain(4); + // expect([4, 5, 6]).not.toContain(5); + + expect([]).not.toContain([]); +}); + +test("toBeTruthy()", () => { + expect("test").toBeTruthy(); + expect(true).toBeTruthy(); + expect(1).toBeTruthy(); + expect({}).toBeTruthy(); + expect([]).toBeTruthy(); + expect(() => {}).toBeTruthy(); + // expect(() => {}).not.toBeTruthy(); + + expect("").not.toBeTruthy(); + expect(0).not.toBeTruthy(); + expect(-0).not.toBeTruthy(); + expect(NaN).not.toBeTruthy(); + expect(0n).not.toBeTruthy(); + expect(false).not.toBeTruthy(); + expect(null).not.toBeTruthy(); + expect(undefined).not.toBeTruthy(); +}); + +test("toBeUndefined()", () => { + expect(undefined).toBeUndefined(); + // expect(undefined).not.toBeUndefined(); + + expect(null).not.toBeUndefined(); + expect(null).not.not.not.toBeUndefined(); + expect(0).not.toBeUndefined(); + expect("hello defined").not.toBeUndefined(); +}); + +test("toBeNaN()", () => { + expect(NaN).toBeNaN(); + // expect(NaN).not.toBeNaN(); + + expect(0).not.toBeNaN(); + expect("hello not NaN").not.toBeNaN(); +}); + +test("toBeNull()", () => { + expect(null).toBeNull(); + // expect(null).not.toBeNull(); + + expect(undefined).not.toBeNull(); + expect(0).not.toBeNull(); + expect("hello not null").not.toBeNull(); +}); + +test("toBeDefined()", () => { + expect(0).toBeDefined(); + expect("hello defined").toBeDefined(); + expect(null).toBeDefined(); + // expect(null).not.toBeDefined(); + + expect(undefined).not.toBeDefined(); +}); + +test("toBeFalsy()", () => { + expect("").toBeFalsy(); + expect(0).toBeFalsy(); + expect(-0).toBeFalsy(); + expect(NaN).toBeFalsy(); + expect(0n).toBeFalsy(); + expect(false).toBeFalsy(); + expect(null).toBeFalsy(); + expect(undefined).toBeFalsy(); + // expect(undefined).not.toBeFalsy(); + + expect("hello not falsy").not.toBeFalsy(); + expect("hello not falsy").not.not.not.toBeFalsy(); + expect(1).not.toBeFalsy(); + expect(true).not.toBeFalsy(); + expect({}).not.toBeFalsy(); + expect([]).not.toBeFalsy(); + expect(() => {}).not.toBeFalsy(); +}); |