diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses.cpp | 62 | ||||
-rw-r--r-- | src/bun.js/bindings/generated_classes.zig | 6 | ||||
-rw-r--r-- | src/bun.js/test/expect.zig | 102 | ||||
-rw-r--r-- | src/bun.js/test/jest.classes.ts | 8 |
4 files changed, 178 insertions, 0 deletions
diff --git a/src/bun.js/bindings/ZigGeneratedClasses.cpp b/src/bun.js/bindings/ZigGeneratedClasses.cpp index 245010158..25aca16c4 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses.cpp +++ b/src/bun.js/bindings/ZigGeneratedClasses.cpp @@ -2693,9 +2693,15 @@ JSC_DECLARE_CUSTOM_GETTER(jsExpectConstructor); extern "C" void ExpectClass__finalize(void*); extern "C" JSC_DECLARE_HOST_FUNCTION(ExpectClass__call); +extern "C" EncodedJSValue ExpectPrototype__fail(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(ExpectPrototype__failCallback); + extern "C" JSC::EncodedJSValue ExpectPrototype__getNot(void* ptr, JSC::EncodedJSValue thisValue, JSC::JSGlobalObject* lexicalGlobalObject); JSC_DECLARE_CUSTOM_GETTER(ExpectPrototype__notGetterWrap); +extern "C" EncodedJSValue ExpectPrototype___pass(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(ExpectPrototype__passCallback); + extern "C" JSC::EncodedJSValue ExpectPrototype__getRejects(void* ptr, JSC::EncodedJSValue thisValue, JSC::JSGlobalObject* lexicalGlobalObject); JSC_DECLARE_CUSTOM_GETTER(ExpectPrototype__rejectsGetterWrap); @@ -2879,7 +2885,9 @@ JSC_DECLARE_HOST_FUNCTION(ExpectPrototype__toThrowErrorMatchingSnapshotCallback) STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSExpectPrototype, JSExpectPrototype::Base); static const HashTableValue JSExpectPrototypeTableValues[] = { + { "fail"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__failCallback, 1 } }, { "not"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, ExpectPrototype__notGetterWrap, 0 } }, + { "pass"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__passCallback, 1 } }, { "rejects"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, ExpectPrototype__rejectsGetterWrap, 0 } }, { "resolves"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, ExpectPrototype__resolvesGetterWrap, 0 } }, { "toBe"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toBeCallback, 1 } }, @@ -2956,6 +2964,33 @@ JSC_DEFINE_CUSTOM_GETTER(jsExpectConstructor, (JSGlobalObject * lexicalGlobalObj return JSValue::encode(globalObject->JSExpectConstructor()); } +JSC_DEFINE_HOST_FUNCTION(ExpectPrototype__failCallback, (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); + +#ifdef BUN_DEBUG + /** View the file name of the JS file that called this function + * from a debugger */ + SourceOrigin sourceOrigin = callFrame->callerSourceOrigin(vm); + const char* fileName = sourceOrigin.string().utf8().data(); + static const char* lastFileName = nullptr; + if (lastFileName != fileName) { + lastFileName = fileName; + } +#endif + + return ExpectPrototype__fail(thisObject->wrapped(), lexicalGlobalObject, callFrame); +} + JSC_DEFINE_CUSTOM_GETTER(ExpectPrototype__notGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) { auto& vm = lexicalGlobalObject->vm(); @@ -2968,6 +3003,33 @@ JSC_DEFINE_CUSTOM_GETTER(ExpectPrototype__notGetterWrap, (JSGlobalObject * lexic RELEASE_AND_RETURN(throwScope, result); } +JSC_DEFINE_HOST_FUNCTION(ExpectPrototype__passCallback, (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); + +#ifdef BUN_DEBUG + /** View the file name of the JS file that called this function + * from a debugger */ + SourceOrigin sourceOrigin = callFrame->callerSourceOrigin(vm); + const char* fileName = sourceOrigin.string().utf8().data(); + static const char* lastFileName = nullptr; + if (lastFileName != fileName) { + lastFileName = fileName; + } +#endif + + return ExpectPrototype___pass(thisObject->wrapped(), lexicalGlobalObject, callFrame); +} + JSC_DEFINE_CUSTOM_GETTER(ExpectPrototype__rejectsGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) { auto& vm = lexicalGlobalObject->vm(); diff --git a/src/bun.js/bindings/generated_classes.zig b/src/bun.js/bindings/generated_classes.zig index 947be7a51..e8cc701a3 100644 --- a/src/bun.js/bindings/generated_classes.zig +++ b/src/bun.js/bindings/generated_classes.zig @@ -883,8 +883,12 @@ pub const JSExpect = struct { @compileLog("Expect.finalize is not a finalizer"); } + if (@TypeOf(Expect.fail) != CallbackType) + @compileLog("Expected Expect.fail to be a callback but received " ++ @typeName(@TypeOf(Expect.fail))); if (@TypeOf(Expect.getNot) != GetterTypeWithThisValue) @compileLog("Expected Expect.getNot to be a getter with thisValue"); + if (@TypeOf(Expect._pass) != CallbackType) + @compileLog("Expected Expect._pass to be a callback but received " ++ @typeName(@TypeOf(Expect._pass))); if (@TypeOf(Expect.getRejects) != GetterTypeWithThisValue) @compileLog("Expected Expect.getRejects to be a getter with thisValue"); if (@TypeOf(Expect.getResolves) != GetterTypeWithThisValue) @@ -1037,6 +1041,7 @@ pub const JSExpect = struct { if (@TypeOf(Expect.call) != StaticCallbackType) @compileLog("Expected Expect.call to be a static callback"); if (!JSC.is_bindgen) { + @export(Expect._pass, .{ .name = "ExpectPrototype___pass" }); @export(Expect.addSnapshotSerializer, .{ .name = "ExpectClass__addSnapshotSerializer" }); @export(Expect.any, .{ .name = "ExpectClass__any" }); @export(Expect.anything, .{ .name = "ExpectClass__anything" }); @@ -1045,6 +1050,7 @@ pub const JSExpect = struct { @export(Expect.call, .{ .name = "ExpectClass__call" }); @export(Expect.constructor, .{ .name = "ExpectClass__construct" }); @export(Expect.extend, .{ .name = "ExpectClass__extend" }); + @export(Expect.fail, .{ .name = "ExpectPrototype__fail" }); @export(Expect.finalize, .{ .name = "ExpectClass__finalize" }); @export(Expect.getNot, .{ .name = "ExpectPrototype__getNot" }); @export(Expect.getRejects, .{ .name = "ExpectPrototype__getRejects" }); diff --git a/src/bun.js/test/expect.zig b/src/bun.js/test/expect.zig index d6f8ebb12..07fbca03c 100644 --- a/src/bun.js/test/expect.zig +++ b/src/bun.js/test/expect.zig @@ -289,6 +289,108 @@ pub const Expect = struct { return null; } + // pass here has a leading underscore to avoid name collision with the pass variable in other functions + pub fn _pass( + this: *Expect, + globalObject: *JSC.JSGlobalObject, + callFrame: *JSC.CallFrame, + ) callconv(.C) JSC.JSValue { + defer this.postMatch(globalObject); + + const thisValue = callFrame.this(); + const arguments_ = callFrame.arguments(1); + const arguments = arguments_.ptr[0..arguments_.len]; + + var _msg: ZigString = ZigString.Empty; + + if (arguments.len > 0) { + const value = arguments[0]; + value.ensureStillAlive(); + + if (!value.isString()) { + globalObject.throwInvalidArgumentType("pass", "message", "string"); + return .zero; + } + + value.toZigString(&_msg, globalObject); + } else { + _msg = ZigString.fromBytes("passes by .pass() assertion"); + } + + active_test_expectation_counter.actual += 1; + + const not = this.flags.not; + var pass = true; + + if (not) pass = !pass; + if (pass) return thisValue; + + var msg = _msg.toSlice(default_allocator); + defer msg.deinit(); + + if (not) { + const signature = comptime getSignature("pass", "", true); + const fmt = signature ++ "\n\n{s}\n"; + if (Output.enable_ansi_colors) { + globalObject.throw(Output.prettyFmt(fmt, true), .{msg.slice()}); + return .zero; + } + globalObject.throw(Output.prettyFmt(fmt, false), .{msg.slice()}); + return .zero; + } + + // should never reach here + return .zero; + } + + pub fn fail( + this: *Expect, + globalObject: *JSC.JSGlobalObject, + callFrame: *JSC.CallFrame, + ) callconv(.C) JSC.JSValue { + defer this.postMatch(globalObject); + + const thisValue = callFrame.this(); + const arguments_ = callFrame.arguments(1); + const arguments = arguments_.ptr[0..arguments_.len]; + + var _msg: ZigString = ZigString.Empty; + + if (arguments.len > 0) { + const value = arguments[0]; + value.ensureStillAlive(); + + if (!value.isString()) { + globalObject.throwInvalidArgumentType("fail", "message", "string"); + return .zero; + } + + value.toZigString(&_msg, globalObject); + } else { + _msg = ZigString.fromBytes("fails by .fail() assertion"); + } + + active_test_expectation_counter.actual += 1; + + const not = this.flags.not; + var pass = false; + + if (not) pass = !pass; + if (pass) return thisValue; + + var msg = _msg.toSlice(default_allocator); + defer msg.deinit(); + + const signature = comptime getSignature("fail", "", true); + const fmt = signature ++ "\n\n{s}\n"; + if (Output.enable_ansi_colors) { + globalObject.throw(Output.prettyFmt(fmt, true), .{msg.slice()}); + return .zero; + } + globalObject.throw(Output.prettyFmt(fmt, false), .{msg.slice()}); + return .zero; + } + /// Object.is() pub fn toBe( this: *Expect, diff --git a/src/bun.js/test/jest.classes.ts b/src/bun.js/test/jest.classes.ts index e5bf567a9..c337ab4ec 100644 --- a/src/bun.js/test/jest.classes.ts +++ b/src/bun.js/test/jest.classes.ts @@ -108,6 +108,14 @@ export default [ }, }, proto: { + pass: { + fn: "_pass", + length: 1, + }, + fail: { + fn: "fail", + length: 1, + }, toBe: { fn: "toBe", length: 1, |