aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js
diff options
context:
space:
mode:
authorGravatar Dylan Conway <35280289+dylan-conway@users.noreply.github.com> 2023-02-21 11:47:13 -0800
committerGravatar GitHub <noreply@github.com> 2023-02-21 11:47:13 -0800
commitd786dd6c0bd0c8b4f4444ab55cbcb479e8d87b7e (patch)
tree059749b2af3d294d1ac59886123157f86bf3d1a2 /src/bun.js
parente21796acf506094ec39289c868b33a40ca505b74 (diff)
downloadbun-d786dd6c0bd0c8b4f4444ab55cbcb479e8d87b7e.tar.gz
bun-d786dd6c0bd0c8b4f4444ab55cbcb479e8d87b7e.tar.zst
bun-d786dd6c0bd0c8b4f4444ab55cbcb479e8d87b7e.zip
Update test runner output with colors and diffs (#2122)
* add zig-diff * move diff functions * toHaveProperty diff for objects * use formatter * format labels * move work to format, diff when it makes sense * remove comptime, dim equal slices * order before diff * line diffs * add diffz * switch to diffz * add `diffLines()` function * small `prettyFmt()` bug fix * test runner color output * update `toBe()` error output * fix test * diff method, fix crash * fix link test * remove `isRegex`
Diffstat (limited to 'src/bun.js')
-rw-r--r--src/bun.js/api/bun.zig2
-rw-r--r--src/bun.js/bindings/bindings.cpp96
-rw-r--r--src/bun.js/bindings/bindings.zig29
-rw-r--r--src/bun.js/bindings/exports.zig25
-rw-r--r--src/bun.js/bindings/headers.h3
-rw-r--r--src/bun.js/bindings/headers.zig1
-rw-r--r--src/bun.js/test/jest.zig979
7 files changed, 969 insertions, 166 deletions
diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig
index da42e5feb..0e17d089f 100644
--- a/src/bun.js/api/bun.zig
+++ b/src/bun.js/api/bun.zig
@@ -246,6 +246,8 @@ pub fn inspect(
false,
false,
false,
+ false,
+ false,
);
buffered_writer.flush() catch {
return JSC.C.JSValueMakeUndefined(ctx);
diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp
index bb01e4101..c093fad59 100644
--- a/src/bun.js/bindings/bindings.cpp
+++ b/src/bun.js/bindings/bindings.cpp
@@ -97,9 +97,7 @@ static void copyToUWS(WebCore::FetchHeaders* headers, UWSResponse* res)
auto& internalHeaders = headers->internalHeaders();
for (auto& value : internalHeaders.getSetCookieHeaders()) {
- res->writeHeader(std::string_view("set-cookie", 10), std::string_view(
- value.is8Bit() ? reinterpret_cast<const char*>(value.characters8()) : value.utf8().data(), value.length()
- ));
+ res->writeHeader(std::string_view("set-cookie", 10), std::string_view(value.is8Bit() ? reinterpret_cast<const char*>(value.characters8()) : value.utf8().data(), value.length()));
}
for (auto& header : internalHeaders.commonHeaders()) {
@@ -107,8 +105,7 @@ static void copyToUWS(WebCore::FetchHeaders* headers, UWSResponse* res)
auto& value = header.value;
res->writeHeader(
std::string_view(name.is8Bit() ? reinterpret_cast<const char*>(name.characters8()) : name.utf8().data(), name.length()),
- std::string_view(value.is8Bit() ? reinterpret_cast<const char*>(value.characters8()) : value.utf8().data(), value.length())
- );
+ std::string_view(value.is8Bit() ? reinterpret_cast<const char*>(value.characters8()) : value.utf8().data(), value.length()));
}
for (auto& header : internalHeaders.uncommonHeaders()) {
@@ -116,8 +113,7 @@ static void copyToUWS(WebCore::FetchHeaders* headers, UWSResponse* res)
auto& value = header.value;
res->writeHeader(
std::string_view(name.is8Bit() ? reinterpret_cast<const char*>(name.characters8()) : name.utf8().data(), name.length()),
- std::string_view(value.is8Bit() ? reinterpret_cast<const char*>(value.characters8()) : value.utf8().data(), value.length())
- );
+ std::string_view(value.is8Bit() ? reinterpret_cast<const char*>(value.characters8()) : value.utf8().data(), value.length()));
}
}
@@ -718,12 +714,11 @@ WebCore__FetchHeaders* WebCore__FetchHeaders__createEmpty()
return new WebCore::FetchHeaders({ WebCore::FetchHeaders::Guard::None, {} });
}
void WebCore__FetchHeaders__append(WebCore__FetchHeaders* headers, const ZigString* arg1, const ZigString* arg2,
- JSC__JSGlobalObject* lexicalGlobalObject)
+ JSC__JSGlobalObject* lexicalGlobalObject)
{
auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());
WebCore::propagateException(*lexicalGlobalObject, throwScope,
- headers->append(Zig::toString(*arg1), Zig::toString(*arg2))
- );
+ headers->append(Zig::toString(*arg1), Zig::toString(*arg2)));
}
WebCore__FetchHeaders* WebCore__FetchHeaders__cast_(JSC__JSValue JSValue0, JSC__VM* vm)
{
@@ -752,8 +747,7 @@ WebCore__FetchHeaders* WebCore__FetchHeaders__createFromJS(JSC__JSGlobalObject*
// ExceptionOr<void>. So we need to check for the exception and, if set,
// translate it to JSValue and throw it.
WebCore::propagateException(*lexicalGlobalObject, throwScope,
- headers->fill(WTFMove(init.value()))
- );
+ headers->fill(WTFMove(init.value())));
}
return headers;
}
@@ -770,8 +764,7 @@ JSC__JSValue WebCore__FetchHeaders__clone(WebCore__FetchHeaders* headers, JSC__J
Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(arg1);
auto* clone = new WebCore::FetchHeaders({ WebCore::FetchHeaders::Guard::None, {} });
WebCore::propagateException(*arg1, throwScope,
- clone->fill(*headers)
- );
+ clone->fill(*headers));
return JSC::JSValue::encode(WebCore::toJSNewlyCreated(arg1, globalObject, WTFMove(clone)));
}
@@ -780,8 +773,7 @@ WebCore__FetchHeaders* WebCore__FetchHeaders__cloneThis(WebCore__FetchHeaders* h
auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());
auto* clone = new WebCore::FetchHeaders({ WebCore::FetchHeaders::Guard::None, {} });
WebCore::propagateException(*lexicalGlobalObject, throwScope,
- clone->fill(*headers)
- );
+ clone->fill(*headers));
return clone;
}
@@ -936,9 +928,8 @@ JSC__JSValue WebCore__FetchHeaders__createValue(JSC__JSGlobalObject* arg0, Strin
}
Ref<WebCore::FetchHeaders> headers = WebCore::FetchHeaders::create();
- WebCore::propagateException(*arg0, throwScope,
- headers->fill(WebCore::FetchHeaders::Init(WTFMove(pairs)))
- );
+ WebCore::propagateException(*arg0, throwScope,
+ headers->fill(WebCore::FetchHeaders::Init(WTFMove(pairs))));
pairs.releaseBuffer();
return JSC::JSValue::encode(WebCore::toJSNewlyCreated(arg0, reinterpret_cast<Zig::GlobalObject*>(arg0), WTFMove(headers)));
}
@@ -965,15 +956,13 @@ void WebCore__FetchHeaders__put_(WebCore__FetchHeaders* headers, const ZigString
{
auto throwScope = DECLARE_THROW_SCOPE(global->vm());
WebCore::propagateException(*global, throwScope,
- headers->set(Zig::toString(*arg1), Zig::toString(*arg2))
- );
+ headers->set(Zig::toString(*arg1), Zig::toString(*arg2)));
}
void WebCore__FetchHeaders__remove(WebCore__FetchHeaders* headers, const ZigString* arg1, JSC__JSGlobalObject* global)
{
auto throwScope = DECLARE_THROW_SCOPE(global->vm());
WebCore::propagateException(*global, throwScope,
- headers->remove(Zig::toString(*arg1))
- );
+ headers->remove(Zig::toString(*arg1)));
}
void WebCore__FetchHeaders__fastRemove_(WebCore__FetchHeaders* headers, unsigned char headerName)
@@ -3762,6 +3751,40 @@ restart:
}
}
+inline bool propertyCompare(const std::pair<String, JSValue>& a, const std::pair<String, JSValue>& b)
+{
+ return codePointCompare(a.first.impl(), b.first.impl()) < 0;
+}
+
+void JSC__JSValue__forEachPropertyOrdered(JSC__JSValue JSValue0, JSC__JSGlobalObject* globalObject, void* arg2, void (*iter)(JSC__JSGlobalObject* arg0, void* ctx, ZigString* arg2, JSC__JSValue JSValue3, bool isSymbol))
+{
+ JSC::JSValue value = JSC::JSValue::decode(JSValue0);
+ JSC::JSObject* object = value.getObject();
+ if (!object)
+ return;
+
+ JSC::VM& vm = globalObject->vm();
+ auto scope = DECLARE_CATCH_SCOPE(vm);
+
+ JSC::PropertyNameArray properties(vm, PropertyNameMode::StringsAndSymbols, PrivateSymbolMode::Exclude);
+ JSC::JSObject::getOwnPropertyNames(object, globalObject, properties, DontEnumPropertiesMode::Include);
+
+ Vector<std::pair<String, JSValue>> ordered_properties;
+ for (auto property : properties) {
+ JSValue propertyValue = object->getDirect(vm, property);
+ ordered_properties.append(std::pair<String, JSValue>(property.isSymbol() && !property.isPrivateName() ? property.impl() : property.string(), propertyValue));
+ }
+
+ std::sort(ordered_properties.begin(), ordered_properties.end(), propertyCompare);
+
+ for (auto item : ordered_properties) {
+ ZigString key = toZigString(item.first);
+ JSValue propertyValue = item.second;
+ JSC::EnsureStillAliveScope ensureStillAliveScope(propertyValue);
+ iter(globalObject, arg2, &key, JSC::JSValue::encode(propertyValue), propertyValue.isSymbol());
+ }
+}
+
extern "C" JSC__JSValue JSC__JSValue__createRopeString(JSC__JSValue JSValue0, JSC__JSValue JSValue1, JSC__JSGlobalObject* globalObject)
{
return JSValue::encode(JSC::jsString(globalObject, JSC::JSValue::decode(JSValue0).toString(globalObject), JSC::JSValue::decode(JSValue1).toString(globalObject)));
@@ -3796,39 +3819,44 @@ extern "C" void JSC__JSGlobalObject__queueMicrotaskJob(JSC__JSGlobalObject* arg0
JSC::JSValue::decode(JSValue4));
}
-extern "C" JSC__AbortSignal* JSC__AbortSignal__signal(JSC__AbortSignal* arg0, JSC__JSValue JSValue1) {
+extern "C" JSC__AbortSignal* JSC__AbortSignal__signal(JSC__AbortSignal* arg0, JSC__JSValue JSValue1)
+{
WebCore::AbortSignal* abortSignal = reinterpret_cast<WebCore::AbortSignal*>(arg0);
abortSignal->signalAbort(JSC::JSValue::decode(JSValue1));
return arg0;
}
-extern "C" bool JSC__AbortSignal__aborted(JSC__AbortSignal* arg0) {
+extern "C" bool JSC__AbortSignal__aborted(JSC__AbortSignal* arg0)
+{
WebCore::AbortSignal* abortSignal = reinterpret_cast<WebCore::AbortSignal*>(arg0);
return abortSignal->aborted();
}
-extern "C" JSC__JSValue JSC__AbortSignal__abortReason(JSC__AbortSignal* arg0) {
+extern "C" JSC__JSValue JSC__AbortSignal__abortReason(JSC__AbortSignal* arg0)
+{
WebCore::AbortSignal* abortSignal = reinterpret_cast<WebCore::AbortSignal*>(arg0);
return JSC::JSValue::encode(abortSignal->reason().getValue());
}
-
-extern "C" JSC__AbortSignal* JSC__AbortSignal__ref(JSC__AbortSignal* arg0) {
+extern "C" JSC__AbortSignal* JSC__AbortSignal__ref(JSC__AbortSignal* arg0)
+{
WebCore::AbortSignal* abortSignal = reinterpret_cast<WebCore::AbortSignal*>(arg0);
abortSignal->ref();
return arg0;
}
-extern "C" JSC__AbortSignal* JSC__AbortSignal__unref(JSC__AbortSignal* arg0) {
+extern "C" JSC__AbortSignal* JSC__AbortSignal__unref(JSC__AbortSignal* arg0)
+{
WebCore::AbortSignal* abortSignal = reinterpret_cast<WebCore::AbortSignal*>(arg0);
abortSignal->deref();
return arg0;
}
-extern "C" JSC__AbortSignal* JSC__AbortSignal__addListener(JSC__AbortSignal* arg0, void* ctx, void (*callback)(void* ctx, JSC__JSValue reason)) {
+extern "C" JSC__AbortSignal* JSC__AbortSignal__addListener(JSC__AbortSignal* arg0, void* ctx, void (*callback)(void* ctx, JSC__JSValue reason))
+{
WebCore::AbortSignal* abortSignal = reinterpret_cast<WebCore::AbortSignal*>(arg0);
-
- if(abortSignal->aborted()){
+
+ if (abortSignal->aborted()) {
callback(ctx, JSC::JSValue::encode(abortSignal->reason().getValue()));
return arg0;
}
@@ -3859,7 +3887,7 @@ extern "C" JSC__JSValue JSC__AbortSignal__createAbortError(const ZigString* mess
error->putDirect(
vm, vm.propertyNames->name,
JSC::JSValue(JSC::jsOwnedString(vm, ABORT_ERROR_NAME)),
- 0);
+ 0);
if (code.len > 0) {
auto clientData = WebCore::clientData(vm);
@@ -3881,7 +3909,7 @@ extern "C" JSC__JSValue JSC__AbortSignal__createTimeoutError(const ZigString* me
error->putDirect(
vm, vm.propertyNames->name,
JSC::JSValue(JSC::jsOwnedString(vm, TIMEOUT_ERROR_NAME)),
- 0);
+ 0);
if (code.len > 0) {
auto clientData = WebCore::clientData(vm);
diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig
index 64b2b060d..800fd0af9 100644
--- a/src/bun.js/bindings/bindings.zig
+++ b/src/bun.js/bindings/bindings.zig
@@ -211,12 +211,12 @@ pub const ZigString = extern struct {
pub fn substring(this: ZigString, offset: usize, maxlen: usize) ZigString {
var len: usize = undefined;
- if(maxlen == 0){
+ if (maxlen == 0) {
len = this.len;
- }else {
+ } else {
len = @max(this.len, maxlen);
}
-
+
if (this.is16Bit()) {
return ZigString.from16Slice(this.utf16SliceAligned()[@min(this.len, offset)..len]);
}
@@ -2911,6 +2911,15 @@ pub const JSValue = enum(JSValueReprInt) {
cppFn("forEachProperty", .{ this, globalThis, ctx, callback });
}
+ pub fn forEachPropertyOrdered(
+ this: JSValue,
+ globalObject: *JSC.JSGlobalObject,
+ ctx: ?*anyopaque,
+ callback: PropertyIteratorFn,
+ ) void {
+ cppFn("forEachPropertyOrdered", .{ this, globalObject, ctx, callback });
+ }
+
pub fn coerce(this: JSValue, comptime T: type, globalThis: *JSC.JSGlobalObject) T {
return switch (T) {
ZigString => this.getZigString(globalThis),
@@ -3638,6 +3647,19 @@ pub const JSValue = enum(JSValueReprInt) {
return cppFn("strictDeepEquals", .{ this, other, global });
}
+ pub const DiffMethod = enum(u8) {
+ none,
+ character,
+ word,
+ line,
+ };
+
+ pub fn determineDiffMethod(this: JSValue, other: JSValue, global: *JSGlobalObject) DiffMethod {
+ if ((this.isString() and other.isString()) or (this.jsType() == .RegExpObject and other.jsType() == .RegExpObject) or (this.isBuffer(global) and other.isBuffer(global))) return .character;
+ if (this.isObject() and other.isObject()) return .line;
+ return .none;
+ }
+
pub fn asString(this: JSValue) *JSString {
return cppFn("asString", .{
this,
@@ -3852,6 +3874,7 @@ pub const JSValue = enum(JSValueReprInt) {
"fastGet_",
"forEach",
"forEachProperty",
+ "forEachPropertyOrdered",
"fromEntries",
"fromInt64NoTruncate",
"fromUInt64NoTruncate",
diff --git a/src/bun.js/bindings/exports.zig b/src/bun.js/bindings/exports.zig
index 70aae7df3..aeced9a69 100644
--- a/src/bun.js/bindings/exports.zig
+++ b/src/bun.js/bindings/exports.zig
@@ -967,6 +967,8 @@ pub const ZigConsoleClient = struct {
enable_colors,
true,
true,
+ false,
+ false,
)
else if (message_type == .Log) {
_ = console.writer.write("\n") catch 0;
@@ -1015,6 +1017,8 @@ pub const ZigConsoleClient = struct {
enable_colors: bool,
add_newline: bool,
flush: bool,
+ order_properties: bool,
+ quote_strings: bool,
) void {
var fmt: ZigConsoleClient.Formatter = undefined;
defer {
@@ -1026,7 +1030,12 @@ pub const ZigConsoleClient = struct {
}
if (len == 1) {
- fmt = ZigConsoleClient.Formatter{ .remaining_values = &[_]JSValue{}, .globalThis = global };
+ fmt = ZigConsoleClient.Formatter{
+ .remaining_values = &[_]JSValue{},
+ .globalThis = global,
+ .ordered_properties = order_properties,
+ .quote_strings = quote_strings,
+ };
const tag = ZigConsoleClient.Formatter.Tag.get(vals[0], global);
var unbuffered_writer = if (comptime Writer != RawWriter)
@@ -1099,7 +1108,12 @@ pub const ZigConsoleClient = struct {
}
var this_value: JSValue = vals[0];
- fmt = ZigConsoleClient.Formatter{ .remaining_values = vals[0..len][1..], .globalThis = global };
+ fmt = ZigConsoleClient.Formatter{
+ .remaining_values = vals[0..len][1..],
+ .globalThis = global,
+ .ordered_properties = order_properties,
+ .quote_strings = quote_strings,
+ };
var tag: ZigConsoleClient.Formatter.Tag.Result = undefined;
var any = false;
@@ -1163,6 +1177,7 @@ pub const ZigConsoleClient = struct {
failed: bool = false,
estimated_line_length: usize = 0,
always_newline_scope: bool = false,
+ ordered_properties: bool = false,
pub fn goodTimeForANewLine(this: *@This()) bool {
if (this.estimated_line_length > 80) {
@@ -2541,7 +2556,11 @@ pub const ZigConsoleClient = struct {
.parent = value,
};
- value.forEachProperty(this.globalThis, &iter, Iterator.forEach);
+ if (this.ordered_properties) {
+ value.forEachPropertyOrdered(this.globalThis, &iter, Iterator.forEach);
+ } else {
+ value.forEachProperty(this.globalThis, &iter, Iterator.forEach);
+ }
if (iter.i == 0) {
if (value.isClass(this.globalThis) and !value.isCallable(this.globalThis.vm()))
diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h
index a81695ac1..50c37dde6 100644
--- a/src/bun.js/bindings/headers.h
+++ b/src/bun.js/bindings/headers.h
@@ -1,5 +1,5 @@
// clang-format off
-//-- AUTOGENERATED FILE -- 1676656020
+//-- AUTOGENERATED FILE -- 1676945760
#pragma once
#include <stddef.h>
@@ -296,6 +296,7 @@ CPP_DECL bool JSC__JSValue__eqlValue(JSC__JSValue JSValue0, JSC__JSValue JSValue
CPP_DECL JSC__JSValue JSC__JSValue__fastGet_(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, unsigned char arg2);
CPP_DECL void JSC__JSValue__forEach(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, void* arg2, void(* ArgFn3)(JSC__VM* arg0, JSC__JSGlobalObject* arg1, void* arg2, JSC__JSValue JSValue3)) __attribute__((nonnull (3)));
CPP_DECL void JSC__JSValue__forEachProperty(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, void* arg2, void(* ArgFn3)(JSC__JSGlobalObject* arg0, void* arg1, ZigString* arg2, JSC__JSValue JSValue3, bool arg4)) __attribute__((nonnull (3)));
+CPP_DECL void JSC__JSValue__forEachPropertyOrdered(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, void* arg2, void(* ArgFn3)(JSC__JSGlobalObject* arg0, void* arg1, ZigString* arg2, JSC__JSValue JSValue3, bool arg4)) __attribute__((nonnull (3)));
CPP_DECL JSC__JSValue JSC__JSValue__fromEntries(JSC__JSGlobalObject* arg0, ZigString* arg1, ZigString* arg2, size_t arg3, bool arg4);
CPP_DECL JSC__JSValue JSC__JSValue__fromInt64NoTruncate(JSC__JSGlobalObject* arg0, int64_t arg1);
CPP_DECL JSC__JSValue JSC__JSValue__fromUInt64NoTruncate(JSC__JSGlobalObject* arg0, uint64_t arg1);
diff --git a/src/bun.js/bindings/headers.zig b/src/bun.js/bindings/headers.zig
index ac936e280..12c72a717 100644
--- a/src/bun.js/bindings/headers.zig
+++ b/src/bun.js/bindings/headers.zig
@@ -209,6 +209,7 @@ pub extern fn JSC__JSValue__eqlValue(JSValue0: JSC__JSValue, JSValue1: JSC__JSVa
pub extern fn JSC__JSValue__fastGet_(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: u8) JSC__JSValue;
pub extern fn JSC__JSValue__forEach(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?*const fn (*bindings.VM, *bindings.JSGlobalObject, ?*anyopaque, JSC__JSValue) callconv(.C) void) void;
pub extern fn JSC__JSValue__forEachProperty(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?*const fn (*bindings.JSGlobalObject, ?*anyopaque, [*c]ZigString, JSC__JSValue, bool) callconv(.C) void) void;
+pub extern fn JSC__JSValue__forEachPropertyOrdered(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?*const fn (*bindings.JSGlobalObject, ?*anyopaque, [*c]ZigString, JSC__JSValue, bool) callconv(.C) void) void;
pub extern fn JSC__JSValue__fromEntries(arg0: *bindings.JSGlobalObject, arg1: [*c]ZigString, arg2: [*c]ZigString, arg3: usize, arg4: bool) JSC__JSValue;
pub extern fn JSC__JSValue__fromInt64NoTruncate(arg0: *bindings.JSGlobalObject, arg1: i64) JSC__JSValue;
pub extern fn JSC__JSValue__fromUInt64NoTruncate(arg0: *bindings.JSGlobalObject, arg1: u64) JSC__JSValue;
diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig
index 1ae0bd51a..90c595037 100644
--- a/src/bun.js/test/jest.zig
+++ b/src/bun.js/test/jest.zig
@@ -8,6 +8,8 @@ const HTTPClient = @import("bun").HTTP;
const NetworkThread = HTTPClient.NetworkThread;
const Environment = @import("../../env.zig");
+const DiffMatchPatch = @import("../../deps/diffz/DiffMatchPatch.zig");
+
const JSC = @import("bun").JSC;
const js = JSC.C;
@@ -61,6 +63,161 @@ fn notImplementedProp(
return null;
}
+pub const DiffFormatter = struct {
+ received: JSValue,
+ expected: JSValue,
+ globalObject: *JSC.JSGlobalObject,
+ not: bool = false,
+
+ pub fn format(this: DiffFormatter, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
+ var received_buf = MutableString.init(default_allocator, 0) catch unreachable;
+ var expected_buf = MutableString.init(default_allocator, 0) catch unreachable;
+ defer {
+ received_buf.deinit();
+ expected_buf.deinit();
+ }
+
+ {
+ var buffered_writer_ = bun.MutableString.BufferedWriter{ .context = &received_buf };
+ var buffered_writer = &buffered_writer_;
+
+ var buf_writer = buffered_writer.writer();
+ const Writer = @TypeOf(buf_writer);
+
+ JSC.ZigConsoleClient.format(
+ .Debug,
+ this.globalObject,
+ @ptrCast([*]const JSValue, &this.received),
+ 1,
+ Writer,
+ Writer,
+ buf_writer,
+ false,
+ false,
+ false,
+ true,
+ true,
+ );
+ buffered_writer.flush() catch unreachable;
+
+ buffered_writer_.context = &expected_buf;
+
+ JSC.ZigConsoleClient.format(
+ .Debug,
+ this.globalObject,
+ @ptrCast([*]const JSValue, &this.expected),
+ 1,
+ Writer,
+ Writer,
+ buf_writer,
+ false,
+ false,
+ false,
+ true,
+ true,
+ );
+ buffered_writer.flush() catch unreachable;
+ }
+
+ const received_slice = received_buf.toOwnedSliceLeaky();
+ const expected_slice = expected_buf.toOwnedSliceLeaky();
+
+ if (this.not) {
+ const not_fmt = "Expected: not <green>{s}<r>";
+ if (Output.enable_ansi_colors) {
+ try writer.print(Output.prettyFmt(not_fmt, true), .{expected_slice});
+ } else {
+ try writer.print(Output.prettyFmt(not_fmt, false), .{expected_slice});
+ }
+ return;
+ }
+
+ const equal_fmt = "<d>{s}<r>";
+ const delete_fmt = "<red>{s}<r>";
+ const insert_fmt = "<green>{s}<r>";
+
+ switch (this.received.determineDiffMethod(this.expected, this.globalObject)) {
+ .none => {
+ const fmt = "Expected: <green>{any}<r>\nReceived: <red>{any}<r>";
+ var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = this.globalObject, .quote_strings = true };
+ if (Output.enable_ansi_colors) {
+ try writer.print(Output.prettyFmt(fmt, true), .{
+ this.expected.toFmt(this.globalObject, &formatter),
+ this.received.toFmt(this.globalObject, &formatter),
+ });
+ return;
+ }
+
+ try writer.print(Output.prettyFmt(fmt, true), .{
+ this.expected.toFmt(this.globalObject, &formatter),
+ this.received.toFmt(this.globalObject, &formatter),
+ });
+ return;
+ },
+ .character => {
+ var dmp = DiffMatchPatch.default;
+ dmp.diff_timeout = 200;
+ var diffs = try dmp.diff(default_allocator, received_slice, expected_slice, false);
+ defer diffs.deinit(default_allocator);
+
+ try writer.writeAll(Output.prettyFmt("Expected: ", true));
+ for (diffs.items) |df| {
+ switch (df.operation) {
+ .delete => continue,
+ .insert => try writer.print(Output.prettyFmt(insert_fmt, true), .{df.text}),
+ .equal => try writer.print(Output.prettyFmt(equal_fmt, true), .{df.text}),
+ }
+ }
+
+ try writer.writeAll(Output.prettyFmt("\nReceived: ", true));
+ for (diffs.items) |df| {
+ switch (df.operation) {
+ .insert => continue,
+ .delete => try writer.print(Output.prettyFmt(delete_fmt, true), .{df.text}),
+ .equal => try writer.print(Output.prettyFmt(equal_fmt, true), .{df.text}),
+ }
+ }
+ return;
+ },
+ .line => {
+ var dmp = DiffMatchPatch.default;
+ dmp.diff_timeout = 200;
+ var diffs = try dmp.diffLines(default_allocator, received_slice, expected_slice);
+ defer diffs.deinit(default_allocator);
+
+ var insert_count: usize = 0;
+ var delete_count: usize = 0;
+
+ for (diffs.items) |df| {
+ switch (df.operation) {
+ .equal => {
+ try writer.print(Output.prettyFmt(equal_fmt, true), .{df.text});
+ },
+ .insert => {
+ for (df.text) |c| {
+ if (c == '\n') insert_count += 1;
+ }
+ try writer.print(Output.prettyFmt(insert_fmt, true), .{df.text});
+ },
+ .delete => {
+ for (df.text) |c| {
+ if (c == '\n') delete_count += 1;
+ }
+ try writer.print(Output.prettyFmt(delete_fmt, true), .{df.text});
+ },
+ }
+ }
+
+ try writer.print(Output.prettyFmt("\n\n<green>- Expected - {d}<r>\n", true), .{insert_count});
+ try writer.print(Output.prettyFmt("<red>+ Received + {d}<r>", true), .{delete_count});
+ return;
+ },
+ .word => {},
+ }
+ return;
+ }
+};
+
const ArrayIdentityContext = @import("../../identity_context.zig").ArrayIdentityContext;
pub const TestRunner = struct {
tests: TestRunner.Test.List = .{},
@@ -327,38 +484,89 @@ pub const Expect = struct {
}
active_test_expectation_counter.actual += 1;
- const left = arguments[0];
- left.ensureStillAlive();
- const right = Expect.capturedValueGetCached(thisValue) orelse {
+ const right = arguments[0];
+ right.ensureStillAlive();
+ const left = Expect.capturedValueGetCached(thisValue) orelse {
globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
return .zero;
};
- right.ensureStillAlive();
+ left.ensureStillAlive();
const not = this.op.contains(.not);
- var pass = left.isSameValue(right, globalObject);
+ var pass = right.isSameValue(left, globalObject);
if (comptime Environment.allow_assert) {
- std.debug.assert(pass == JSC.C.JSValueIsStrictEqual(globalObject, left.asObjectRef(), right.asObjectRef()));
+ std.debug.assert(pass == JSC.C.JSValueIsStrictEqual(globalObject, right.asObjectRef(), left.asObjectRef()));
}
if (not) pass = !pass;
if (pass) return thisValue;
// 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()) });
+ var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject, .quote_strings = true };
+ if (not) {
+ const signature = comptime getSignature("toBe", "<green>expected<r>", true);
+ const fmt = signature ++ "\n\nExpected: not <green>{any}<r>\n";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{right.toFmt(globalObject, &formatter)});
+ return .zero;
+ }
+ globalObject.throw(Output.prettyFmt(fmt, false), .{right.toFmt(globalObject, &formatter)});
+ return .zero;
}
- 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) });
+ const signature = comptime getSignature("toBe", "<green>expected<r>", false);
+ if (left.deepEquals(right, globalObject) or left.strictDeepEquals(right, globalObject)) {
+ const fmt = signature ++
+ "\n\n<d>If this test should pass, replace \"toBe\" with \"toEqual\" or \"toStrictEqual\"<r>" ++
+ "\n\nExpected: <green>{any}<r>\n" ++
+ "Received: serializes to the same string\n";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{right.toFmt(globalObject, &formatter)});
+ return .zero;
+ }
+ globalObject.throw(Output.prettyFmt(fmt, false), .{right.toFmt(globalObject, &formatter)});
+ return .zero;
+ }
+
+ if (right.isString() and left.isString()) {
+ const diff_format = DiffFormatter{
+ .expected = right,
+ .received = left,
+ .globalObject = globalObject,
+ .not = not,
+ };
+ const fmt = signature ++ "\n\n{any}\n";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{diff_format});
+ return .zero;
+ }
+ globalObject.throw(Output.prettyFmt(fmt, false), .{diff_format});
+ return .zero;
}
+
+ const fmt = signature ++ "\n\nExpected: <green>{any}<r>\nReceived: <red>{any}<r>\n";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{
+ right.toFmt(globalObject, &formatter),
+ left.toFmt(globalObject, &formatter),
+ });
+ return .zero;
+ }
+ globalObject.throw(Output.prettyFmt(fmt, false), .{
+ right.toFmt(globalObject, &formatter),
+ left.toFmt(globalObject, &formatter),
+ });
return .zero;
}
+ pub fn getSignature(comptime matcher_name: string, comptime args: string, comptime not: bool) string {
+ const received = "<d>expect(<r><red>received<r><d>).<r>";
+ comptime if (not) {
+ return received ++ "not<d>.<r>" ++ matcher_name ++ "<d>(<r>" ++ args ++ "<d>)<r>";
+ };
+ return received ++ matcher_name ++ "<d>(<r>" ++ args ++ "<d>)<r>";
+ }
+
pub fn toHaveLength(
this: *Expect,
globalObject: *JSC.JSGlobalObject,
@@ -438,10 +646,27 @@ pub const Expect = struct {
// 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 });
+ const expected_line = "Expected length: not <green>{d}<r>\n";
+ const fmt = comptime getSignature("toHaveLength", "<green>expected<r>", true) ++ "\n\n" ++ expected_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{expected_length});
+ return .zero;
+ }
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{expected_length});
+ return .zero;
+ }
+
+ const expected_line = "Expected length: <green>{d}<r>\n";
+ const received_line = "Received length: <red>{d}<r>\n";
+ const fmt = comptime getSignature("toHaveLength", "<green>expected<r>", false) ++ "\n\n" ++
+ expected_line ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{ expected_length, actual_length });
+ return .zero;
}
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{ expected_length, actual_length });
return .zero;
}
@@ -501,12 +726,30 @@ pub const Expect = struct {
if (pass) return thisValue;
// handle failure
- var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ const value_fmt = value.toFmt(globalObject, &formatter);
+ const expected_fmt = expected.toFmt(globalObject, &formatter);
if (not) {
- globalObject.throw("Expected to not contain \"{any}\"", .{expected.toFmt(globalObject, &fmt)});
- } else {
- globalObject.throw("Expected to contain \"{any}\"", .{expected.toFmt(globalObject, &fmt)});
+ const expected_line = "Expected to contain: not <green>{any}<r>\n";
+ const fmt = comptime getSignature("toContain", "<green>expected<r>", true) ++ "\n\n" ++ expected_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{expected_fmt});
+ return .zero;
+ }
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{expected_fmt});
+ return .zero;
+ }
+
+ const expected_line = "Expected to contain: <green>{any}<r>\n";
+ const received_line = "Received: <red>{any}<r>\n";
+ const fmt = comptime getSignature("toContain", "<green>expected<r>", false) ++ "\n\n" ++ expected_line ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{ expected_fmt, value_fmt });
+ return .zero;
}
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{ expected_fmt, value_fmt });
return .zero;
}
@@ -536,12 +779,28 @@ pub const Expect = struct {
if (pass) return thisValue;
// handle failure
- var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ const value_fmt = value.toFmt(globalObject, &formatter);
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)});
+ const received_line = "Received: <red>{any}<r>\n";
+ const fmt = comptime getSignature("toBeTruthy", "", true) ++ "\n\n" ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{value_fmt});
+ return .zero;
+ }
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{value_fmt});
+ return .zero;
+ }
+
+ const received_line = "Received: <red>{any}<r>\n";
+ const fmt = comptime getSignature("toBeTruthy", "", false) ++ "\n\n" ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{value_fmt});
+ return .zero;
}
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{value_fmt});
return .zero;
}
@@ -564,12 +823,28 @@ pub const Expect = struct {
if (pass) return thisValue;
// handle failure
- var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ const value_fmt = value.toFmt(globalObject, &formatter);
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)});
+ const received_line = "Received: <red>{any}<r>\n";
+ const fmt = comptime getSignature("toBeUndefined", "", true) ++ "\n\n" ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{value_fmt});
+ return .zero;
+ }
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{value_fmt});
+ return .zero;
+ }
+
+ const received_line = "Received: <red>{any}<r>\n";
+ const fmt = comptime getSignature("toBeUndefined", "", false) ++ "\n\n" ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{value_fmt});
+ return .zero;
}
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{value_fmt});
return .zero;
}
@@ -596,12 +871,28 @@ pub const Expect = struct {
if (pass) return thisValue;
// handle failure
- var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ const value_fmt = value.toFmt(globalObject, &formatter);
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)});
+ const received_line = "Received: <red>{any}<r>\n";
+ const fmt = comptime getSignature("toBeNaN", "", true) ++ "\n\n" ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{value_fmt});
+ return .zero;
+ }
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{value_fmt});
+ return .zero;
+ }
+
+ const received_line = "Received: <red>{any}<r>\n";
+ const fmt = comptime getSignature("toBeNaN", "", false) ++ "\n\n" ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{value_fmt});
+ return .zero;
}
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{value_fmt});
return .zero;
}
@@ -623,12 +914,28 @@ pub const Expect = struct {
if (pass) return thisValue;
// handle failure
- var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ const value_fmt = value.toFmt(globalObject, &formatter);
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)});
+ const received_line = "Received: <red>{any}<r>\n";
+ const fmt = comptime getSignature("toBeNull", "", true) ++ "\n\n" ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{value_fmt});
+ return .zero;
+ }
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{value_fmt});
+ return .zero;
+ }
+
+ const received_line = "Received: <red>{any}<r>\n";
+ const fmt = comptime getSignature("toBeNull", "", false) ++ "\n\n" ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{value_fmt});
+ return .zero;
}
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{value_fmt});
return .zero;
}
@@ -650,12 +957,28 @@ pub const Expect = struct {
if (pass) return thisValue;
// handle failure
- var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ const value_fmt = value.toFmt(globalObject, &formatter);
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)});
+ const received_line = "Received: <red>{any}<r>\n";
+ const fmt = comptime getSignature("toBeDefined", "", true) ++ "\n\n" ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{value_fmt});
+ return .zero;
+ }
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{value_fmt});
+ return .zero;
+ }
+
+ const received_line = "Received: <red>{any}<r>\n";
+ const fmt = comptime getSignature("toBeDefined", "", false) ++ "\n\n" ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{value_fmt});
+ return .zero;
}
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{value_fmt});
return .zero;
}
@@ -680,12 +1003,28 @@ pub const Expect = struct {
if (pass) return thisValue;
// handle failure
- var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ const value_fmt = value.toFmt(globalObject, &formatter);
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)});
+ const received_line = "Received: <red>{any}<r>\n";
+ const fmt = comptime getSignature("toBeFalsy", "", true) ++ "\n\n" ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{value_fmt});
+ return .zero;
+ }
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{value_fmt});
+ return .zero;
+ }
+
+ const received_line = "Received: <red>{any}<r>\n";
+ const fmt = comptime getSignature("toBeFalsy", "", false) ++ "\n\n" ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{value_fmt});
+ return .zero;
}
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{value_fmt});
return .zero;
}
@@ -722,12 +1061,26 @@ pub const Expect = struct {
if (pass) return thisValue;
// handle failure
- var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ const diff_formatter = DiffFormatter{ .received = value, .expected = expected, .globalObject = globalObject, .not = not };
+
if (not) {
- globalObject.throw("Expected values to not be equal:\n\tExpected: {any}\n\tReceived: {any}", .{ expected.toFmt(globalObject, &fmt), value.toFmt(globalObject, &fmt) });
- } else {
- globalObject.throw("Expected values to be equal:\n\tExpected: {any}\n\tReceived: {any}", .{ expected.toFmt(globalObject, &fmt), value.toFmt(globalObject, &fmt) });
+ const signature = comptime getSignature("toEqual", "<green>expected<r>", true);
+ const fmt = signature ++ "\n\n{any}\n";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{diff_formatter});
+ return .zero;
+ }
+ globalObject.throw(Output.prettyFmt(fmt, false), .{diff_formatter});
+ return .zero;
}
+
+ const signature = comptime getSignature("toEqual", "<green>expected<r>", false);
+ const fmt = signature ++ "\n\n{any}\n";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{diff_formatter});
+ return .zero;
+ }
+ globalObject.throw(Output.prettyFmt(fmt, false), .{diff_formatter});
return .zero;
}
@@ -764,12 +1117,26 @@ pub const Expect = struct {
if (pass) return thisValue;
// handle failure
- var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ const diff_formatter = DiffFormatter{ .received = value, .expected = expected, .globalObject = globalObject, .not = not };
+
if (not) {
- globalObject.throw("Expected values to not be strictly equal:\n\tExpected: {any}\n\tReceived: {any}", .{ expected.toFmt(globalObject, &fmt), value.toFmt(globalObject, &fmt) });
- } else {
- globalObject.throw("Expected values to be strictly equal:\n\tExpected: {any}\n\tReceived: {any}", .{ expected.toFmt(globalObject, &fmt), value.toFmt(globalObject, &fmt) });
+ const signature = comptime getSignature("toStrictEqual", "<green>expected<r>", true);
+ const fmt = signature ++ "\n\n{any}\n";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{diff_formatter});
+ return .zero;
+ }
+ globalObject.throw(Output.prettyFmt(fmt, false), .{diff_formatter});
+ return .zero;
}
+
+ const signature = comptime getSignature("toStrictEqual", "<green>expected<r>", false);
+ const fmt = signature ++ "\n\n{any}\n";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{diff_formatter});
+ return .zero;
+ }
+ globalObject.throw(Output.prettyFmt(fmt, false), .{diff_formatter});
return .zero;
}
@@ -794,8 +1161,8 @@ pub const Expect = struct {
const expected_property_path = arguments[0];
expected_property_path.ensureStillAlive();
- const expected_value: ?JSValue = if (arguments.len > 1) arguments[1] else null;
- if (expected_value) |ev| ev.ensureStillAlive();
+ const expected_property: ?JSValue = if (arguments.len > 1) arguments[1] else null;
+ if (expected_property) |ev| ev.ensureStillAlive();
const value = Expect.capturedValueGetCached(thisValue) orelse {
globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
@@ -812,33 +1179,97 @@ pub const Expect = struct {
var path_string = ZigString.Empty;
expected_property_path.toZigString(&path_string, globalObject);
- const expected_property = value.getIfPropertyExistsFromPath(globalObject, expected_property_path);
+ const received_property = value.getIfPropertyExistsFromPath(globalObject, expected_property_path);
- var pass = !expected_property.isEmpty();
+ var pass = !received_property.isEmpty();
- if (pass and expected_value != null) {
- pass = expected_property.deepEquals(expected_value.?, globalObject);
+ if (pass and expected_property != null) {
+ pass = received_property.deepEquals(expected_property.?, globalObject);
}
if (not) pass = !pass;
if (pass) return thisValue;
// handle failure
- var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject, .quote_strings = true };
if (not) {
- if (!expected_property.isEmpty() and expected_value != null) {
- globalObject.throw("Expected property \"{any}\" to not be equal to: {any}", .{ expected_property.toFmt(globalObject, &fmt), expected_value.?.toFmt(globalObject, &fmt) });
- } else {
- globalObject.throw("Expected \"{any}\" to not have property: {any}", .{ value.toFmt(globalObject, &fmt), expected_property_path.toFmt(globalObject, &fmt) });
+ if (expected_property != null) {
+ const signature = comptime getSignature("toHaveProperty", "<green>path<r><d>, <r><green>value<r>", true);
+ if (!received_property.isEmpty()) {
+ const fmt = signature ++ "\n\nExpected path: <green>{any}<r>\n\nExpected value: not <green>{any}<r>\n";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{
+ expected_property_path.toFmt(globalObject, &formatter),
+ expected_property.?.toFmt(globalObject, &formatter),
+ });
+ return .zero;
+ }
+ globalObject.throw(Output.prettyFmt(fmt, true), .{
+ expected_property_path.toFmt(globalObject, &formatter),
+ expected_property.?.toFmt(globalObject, &formatter),
+ });
+ return .zero;
+ }
}
- } else {
- if (!expected_property.isEmpty() and expected_value != null) {
- globalObject.throw("Expected property \"{any}\" to be equal to: {any}", .{ expected_property.toFmt(globalObject, &fmt), expected_value.?.toFmt(globalObject, &fmt) });
- } else {
- globalObject.throw("Expected \"{any}\" to have property: {any}", .{ value.toFmt(globalObject, &fmt), expected_property_path.toFmt(globalObject, &fmt) });
+
+ const signature = comptime getSignature("toHaveProperty", "<green>path<r>", true);
+ const fmt = signature ++ "\n\nExpected path: not <green>{any}<r>\n\nReceived value: <red>{any}<r>\n";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{
+ expected_property_path.toFmt(globalObject, &formatter),
+ received_property.toFmt(globalObject, &formatter),
+ });
+ return .zero;
+ }
+ globalObject.throw(Output.prettyFmt(fmt, false), .{
+ expected_property_path.toFmt(globalObject, &formatter),
+ received_property.toFmt(globalObject, &formatter),
+ });
+ return .zero;
+ }
+
+ if (expected_property != null) {
+ const signature = comptime getSignature("toHaveProperty", "<green>path<r><d>, <r><green>value<r>", false);
+ if (!received_property.isEmpty()) {
+ // deep equal case
+ const fmt = signature ++ "\n\n{any}\n";
+ const diff_format = DiffFormatter{
+ .received = received_property,
+ .expected = expected_property.?,
+ .globalObject = globalObject,
+ };
+
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{diff_format});
+ return .zero;
+ }
+ globalObject.throw(Output.prettyFmt(fmt, false), .{diff_format});
+ return .zero;
}
+
+ const fmt = signature ++ "\n\nExpected path: <green>{any}<r>\n\nExpected value: <green>{any}<r>\n\n" ++
+ "Unable to find property\n";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{
+ expected_property_path.toFmt(globalObject, &formatter),
+ expected_property.?.toFmt(globalObject, &formatter),
+ });
+ return .zero;
+ }
+ globalObject.throw(Output.prettyFmt(fmt, false), .{
+ expected_property_path.toFmt(globalObject, &formatter),
+ expected_property.?.toFmt(globalObject, &formatter),
+ });
+ return .zero;
}
+ const signature = comptime getSignature("toHaveProperty", "<green>path<r>", false);
+ const fmt = signature ++ "\n\nExpected path: <green>{any}<r>\n\nUnable to find property\n";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{expected_property_path.toFmt(globalObject, &formatter)});
+ return .zero;
+ }
+ globalObject.throw(Output.prettyFmt(fmt, false), .{expected_property_path.toFmt(globalObject, &formatter)});
return .zero;
}
@@ -896,12 +1327,32 @@ pub const Expect = struct {
if (pass) return thisValue;
// handle failure
- var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ const value_fmt = value.toFmt(globalObject, &formatter);
+ const expected_fmt = other_value.toFmt(globalObject, &formatter);
if (not) {
- globalObject.throw("Expected {any} to not be greater than {any}", .{ value.toFmt(globalObject, &fmt), other_value.toFmt(globalObject, &fmt) });
- } else {
- globalObject.throw("Expected {any} to be greater than {any}", .{ value.toFmt(globalObject, &fmt), other_value.toFmt(globalObject, &fmt) });
+ const expected_line = "Expected: not \\> <green>{any}<r>\n";
+ const received_line = "Received: <red>{any}<r>\n";
+ const fmt = comptime getSignature("toBeGreaterThan", "<green>expected<r>", true) ++ "\n\n" ++ expected_line ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{ expected_fmt, value_fmt });
+ return .zero;
+ }
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{ expected_fmt, value_fmt });
+ return .zero;
+ }
+
+ const expected_line = "Expected: \\> <green>{any}<r>\n";
+ const received_line = "Received: <red>{any}<r>\n";
+ const fmt = comptime getSignature("toBeGreaterThan", "<green>expected<r>", false) ++ "\n\n" ++
+ expected_line ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(comptime Output.prettyFmt(fmt, true), .{ expected_fmt, value_fmt });
+ return .zero;
}
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{ expected_fmt, value_fmt });
return .zero;
}
@@ -959,11 +1410,28 @@ pub const Expect = struct {
if (pass) return thisValue;
// handle failure
- var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ const value_fmt = value.toFmt(globalObject, &formatter);
+ const expected_fmt = other_value.toFmt(globalObject, &formatter);
if (not) {
- globalObject.throw("Expected {any} to not be greater than or equal to {any}", .{ value.toFmt(globalObject, &fmt), other_value.toFmt(globalObject, &fmt) });
- } else {
- globalObject.throw("Expected {any} to be greater than or equal to {any}", .{ value.toFmt(globalObject, &fmt), other_value.toFmt(globalObject, &fmt) });
+ const expected_line = "Expected: not \\>= <green>{any}<r>\n";
+ const received_line = "Received: <red>{any}<r>\n";
+ const fmt = comptime getSignature("toBeGreaterThanOrEqual", "<green>expected<r>", true) ++ "\n\n" ++ expected_line ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{ expected_fmt, value_fmt });
+ return .zero;
+ }
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{ expected_fmt, value_fmt });
+ return .zero;
+ }
+
+ const expected_line = "Expected: \\>= <green>{any}<r>\n";
+ const received_line = "Received: <red>{any}<r>\n";
+ const fmt = comptime getSignature("toBeGreaterThanOrEqual", "<green>expected<r>", false) ++ "\n\n" ++ expected_line ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(comptime Output.prettyFmt(fmt, true), .{ expected_fmt, value_fmt });
+ return .zero;
}
return .zero;
}
@@ -1022,11 +1490,28 @@ pub const Expect = struct {
if (pass) return thisValue;
// handle failure
- var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ const value_fmt = value.toFmt(globalObject, &formatter);
+ const expected_fmt = other_value.toFmt(globalObject, &formatter);
if (not) {
- globalObject.throw("Expected {any} to not be less than {any}", .{ value.toFmt(globalObject, &fmt), other_value.toFmt(globalObject, &fmt) });
- } else {
- globalObject.throw("Expected {any} to be less than {any}", .{ value.toFmt(globalObject, &fmt), other_value.toFmt(globalObject, &fmt) });
+ const expected_line = "Expected: not \\< <green>{any}<r>\n";
+ const received_line = "Received: <red>{any}<r>\n";
+ const fmt = comptime getSignature("toBeLessThan", "<green>expected<r>", true) ++ "\n\n" ++ expected_line ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{ expected_fmt, value_fmt });
+ return .zero;
+ }
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{ expected_fmt, value_fmt });
+ return .zero;
+ }
+
+ const expected_line = "Expected: \\< <green>{any}<r>\n";
+ const received_line = "Received: <red>{any}<r>\n";
+ const fmt = comptime getSignature("toBeLessThan", "<green>expected<r>", false) ++ "\n\n" ++ expected_line ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(comptime Output.prettyFmt(fmt, true), .{ expected_fmt, value_fmt });
+ return .zero;
}
return .zero;
}
@@ -1085,11 +1570,28 @@ pub const Expect = struct {
if (pass) return thisValue;
// handle failure
- var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ const value_fmt = value.toFmt(globalObject, &formatter);
+ const expected_fmt = other_value.toFmt(globalObject, &formatter);
if (not) {
- globalObject.throw("Expected {any} to not be less than or equal to {any}", .{ value.toFmt(globalObject, &fmt), other_value.toFmt(globalObject, &fmt) });
- } else {
- globalObject.throw("Expected {any} to be less than or equal to {any}", .{ value.toFmt(globalObject, &fmt), other_value.toFmt(globalObject, &fmt) });
+ const expected_line = "Expected: not \\<= <green>{any}<r>\n";
+ const received_line = "Received: <red>{any}<r>\n";
+ const fmt = comptime getSignature("toBeLessThanOrEqual", "<green>expected<r>", true) ++ "\n\n" ++ expected_line ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{ expected_fmt, value_fmt });
+ return .zero;
+ }
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{ expected_fmt, value_fmt });
+ return .zero;
+ }
+
+ const expected_line = "Expected: \\<= <green>{any}<r>\n";
+ const received_line = "Received: <red>{any}<r>\n";
+ const fmt = comptime getSignature("toBeLessThanOrEqual", "<green>expected<r>", false) ++ "\n\n" ++ expected_line ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(comptime Output.prettyFmt(fmt, true), .{ expected_fmt, value_fmt });
+ return .zero;
}
return .zero;
}
@@ -1108,7 +1610,7 @@ pub const Expect = struct {
active_test_expectation_counter.actual += 1;
- const expected_value = if (arguments.len > 0) brk: {
+ const expected_value: JSValue = if (arguments.len > 0) brk: {
const value = arguments[0];
if (value.isEmptyOrUndefinedOrNull() or !value.isObject() and !value.isString()) {
var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
@@ -1160,59 +1662,286 @@ pub const Expect = struct {
};
const did_throw = result_ != null;
- const matched_expectation = did_throw == !not;
- if (!matched_expectation) {
- if (!not)
- globalObject.throw("Expected function to throw", .{})
- else {
- var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
- globalObject.throw("Expected function not to throw. Received:\n\t{any}", .{result_.?.toFmt(globalObject, &fmt)});
+ if (not) {
+ const signature = comptime getSignature("toThrow", "<green>expected<r>", true);
+
+ if (!did_throw) return thisValue;
+
+ const result: JSValue = result_.?;
+ var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+
+ if (expected_value.isEmpty()) {
+ const signature_no_args = comptime getSignature("toThrow", "", true);
+ if (result.isError()) {
+ const name = result.getIfPropertyExistsImpl(globalObject, "name", 4);
+ const message = result.getIfPropertyExistsImpl(globalObject, "message", 7);
+ const fmt = signature_no_args ++ "\n\nError name: <red>{any}<r>\nError message: <red>{any}<r>\n";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{
+ name.toFmt(globalObject, &formatter),
+ message.toFmt(globalObject, &formatter),
+ });
+ return .zero;
+ }
+ globalObject.throw(Output.prettyFmt(fmt, false), .{
+ name.toFmt(globalObject, &formatter),
+ message.toFmt(globalObject, &formatter),
+ });
+ return .zero;
+ }
+
+ // non error thrown
+ const fmt = signature_no_args ++ "\n\nThrown value: <red>{any}<r>\n";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{result.toFmt(globalObject, &formatter)});
+ return .zero;
+ }
+ globalObject.throw(Output.prettyFmt(fmt, false), .{result.toFmt(globalObject, &formatter)});
+ return .zero;
+ }
+
+ if (expected_value.isString()) {
+ const received_message = result.getIfPropertyExistsImpl(globalObject, "message", 7);
+
+ // partial match (regex not supported)
+ {
+ var expected_string = ZigString.Empty;
+ var received_string = ZigString.Empty;
+ expected_value.toZigString(&expected_string, globalObject);
+ received_message.toZigString(&received_string, globalObject);
+ const expected_slice = expected_string.toSlice(default_allocator);
+ const received_slice = received_string.toSlice(default_allocator);
+ defer {
+ expected_slice.deinit();
+ received_slice.deinit();
+ }
+ if (!strings.contains(received_slice.slice(), expected_slice.slice())) return thisValue;
+ }
+
+ const fmt = signature ++ "\n\nExpected substring: not <green>{any}<r>\nReceived message: <red>{any}<r>\n";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{
+ expected_value.toFmt(globalObject, &formatter),
+ received_message.toFmt(globalObject, &formatter),
+ });
+ return .zero;
+ }
+ globalObject.throw(Output.prettyFmt(fmt, false), .{
+ expected_value.toFmt(globalObject, &formatter),
+ received_message.toFmt(globalObject, &formatter),
+ });
+ return .zero;
}
+ if (expected_value.get(globalObject, "message")) |expected_message| {
+ const received_message = result.getIfPropertyExistsImpl(globalObject, "message", 7);
+ // no partial match for this case
+ if (!expected_message.isSameValue(received_message, globalObject)) return thisValue;
+
+ const fmt = signature ++ "\n\nExpected message: not <green>{any}<r>\n";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{expected_message.toFmt(globalObject, &formatter)});
+ return .zero;
+ }
+ globalObject.throw(Output.prettyFmt(fmt, false), .{expected_message.toFmt(globalObject, &formatter)});
+ return .zero;
+ }
+
+ if (!result.isInstanceOf(globalObject, expected_value)) return thisValue;
+
+ var expected_class = ZigString.Empty;
+ expected_value.getClassName(globalObject, &expected_class);
+ const received_message = result.getIfPropertyExistsImpl(globalObject, "message", 7);
+ const fmt = signature ++ "\n\nExpected constructor: not <green>{s}<r>\n\nReceived message: <red>{any}<r>\n";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{ expected_class, received_message.toFmt(globalObject, &formatter) });
+ return .zero;
+ }
+ globalObject.throw(Output.prettyFmt(fmt, false), .{ expected_class, received_message.toFmt(globalObject, &formatter) });
return .zero;
}
- // If you throw a string, it's treated as the message of an Error
- // If you are expected not to throw and you didn't throw, then you pass
- // If you are expected to throw a specific message and you throw a different one, then you fail.
- if (matched_expectation and (!expected_value.isCell() or not))
- return thisValue;
+ const signature = comptime getSignature("toThrow", "<green>expected<r>", false);
+ if (did_throw) {
+ if (expected_value.isEmpty()) return thisValue;
+
+ const result: JSValue = result_.?;
+ const _received_message = result.get(globalObject, "message");
+
+ if (expected_value.isString()) {
+ if (_received_message) |received_message| {
+ // partial match (regex not supported)
+ var expected_string = ZigString.Empty;
+ var received_string = ZigString.Empty;
+ expected_value.toZigString(&expected_string, globalObject);
+ received_message.toZigString(&received_string, globalObject);
+ const expected_slice = expected_string.toSlice(default_allocator);
+ const received_slice = received_string.toSlice(default_allocator);
+ defer {
+ expected_slice.deinit();
+ received_slice.deinit();
+ }
+ if (strings.contains(received_slice.slice(), expected_slice.slice())) return thisValue;
+ }
- const result = result_ orelse JSC.JSValue.jsUndefined();
+ // error: message from received error does not match expected string
+ var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
- const expected_error = expected_value.toError();
+ if (_received_message) |received_message| {
+ const expected_value_fmt = expected_value.toFmt(globalObject, &formatter);
+ const received_message_fmt = received_message.toFmt(globalObject, &formatter);
+ const fmt = signature ++ "\n\n" ++ "Expected substring: <green>{any}<r>\nReceived message: <red>{any}<r>\n";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{ expected_value_fmt, received_message_fmt });
+ return .zero;
+ }
- if (expected_value.isString() or expected_error != null) {
- const expected = brk: {
- if (expected_value.isString()) break :brk expected_value;
- break :brk expected_error.?.get(globalObject, "message");
- };
- const actual: ?JSValue = if (result.isObject())
- result.get(globalObject, "message")
- else
- null;
- // TODO support partial match
- const pass = brk: {
- if (expected) |expected_message|
- if (actual) |actual_message|
- break :brk expected_message.isSameValue(actual_message, globalObject);
- break :brk false;
- };
+ globalObject.throw(Output.prettyFmt(fmt, false), .{ expected_value_fmt, received_message_fmt });
+ return .zero;
+ }
+
+ const expected_fmt = expected_value.toFmt(globalObject, &formatter);
+ const received_fmt = result.toFmt(globalObject, &formatter);
+ const fmt = signature ++ "\n\n" ++ "Expected substring: <green>{any}<r>\nReceived value: <red>{any}<r>";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{ expected_fmt, received_fmt });
+ return .zero;
+ }
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{ expected_fmt, received_fmt });
+ return .zero;
+ }
+
+ if (expected_value.get(globalObject, "message")) |expected_message| {
+ if (_received_message) |received_message| {
+ if (received_message.isSameValue(expected_message, globalObject)) return thisValue;
+ }
+
+ // error: message from received error does not match expected error message.
+ var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+
+ if (_received_message) |received_message| {
+ const expected_fmt = expected_message.toFmt(globalObject, &formatter);
+ const received_fmt = received_message.toFmt(globalObject, &formatter);
+ const fmt = signature ++ "\n\nExpected message: <green>{any}<r>\nReceived message: <red>{any}<r>\n";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{ expected_fmt, received_fmt });
+ return .zero;
+ }
- if (pass) return thisValue;
- globalObject.throw("\n\tExpected: {s}\n\tReceived: {s}", .{
- if (expected) |message| message.getZigString(globalObject) else ZigString.init("undefined"),
- if (actual) |message| message.getZigString(globalObject) else ZigString.init("undefined"),
+ globalObject.throw(Output.prettyFmt(fmt, false), .{ expected_fmt, received_fmt });
+ return .zero;
+ }
+
+ const expected_fmt = expected_message.toFmt(globalObject, &formatter);
+ const received_fmt = result.toFmt(globalObject, &formatter);
+ const fmt = signature ++ "\n\nExpected message: <green>{any}<r>\nReceived value: <red>{any}<r>\n";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{ expected_fmt, received_fmt });
+ return .zero;
+ }
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{ expected_fmt, received_fmt });
+ return .zero;
+ }
+
+ if (result.isInstanceOf(globalObject, expected_value)) return thisValue;
+
+ // error: received error not instance of received error constructor
+ var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ var expected_class = ZigString.Empty;
+ var received_class = ZigString.Empty;
+ expected_value.getClassName(globalObject, &expected_class);
+ result.getClassName(globalObject, &received_class);
+ const fmt = signature ++ "\n\nExpected constructor: <green>{s}<r>\nReceived constructor: <red>{s}<r>\n\n";
+
+ if (_received_message) |received_message| {
+ const message_fmt = fmt ++ "Received message: <red>{any}<r>\n";
+ const received_message_fmt = received_message.toFmt(globalObject, &formatter);
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(message_fmt, true), .{
+ expected_class,
+ received_class,
+ received_message_fmt,
+ });
+ return .zero;
+ }
+
+ globalObject.throw(Output.prettyFmt(message_fmt, false), .{
+ expected_class,
+ received_class,
+ received_message_fmt,
+ });
+ return .zero;
+ }
+
+ const received_fmt = result.toFmt(globalObject, &formatter);
+ const value_fmt = fmt ++ "Received value: <red>{any}<r>\n";
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(value_fmt, true), .{
+ expected_class,
+ received_class,
+ received_fmt,
+ });
+ return .zero;
+ }
+
+ globalObject.throw(Output.prettyFmt(value_fmt, false), .{
+ expected_class,
+ received_class,
+ received_fmt,
});
return .zero;
}
- if (result.isInstanceOf(globalObject, expected_value)) return thisValue;
- globalObject.throw("\n\tExpected type: {s}\n\tReceived type: {s}", .{
- expected_value.getName(globalObject),
- if (result.get(globalObject, "name")) |name| name.getZigString(globalObject) else ZigString.init("<Unknown>"),
- });
+ // did not throw
+ var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ const received_line = "Received function did not throw\n";
+
+ if (expected_value.isEmpty()) {
+ const fmt = comptime getSignature("toThrow", "", false) ++ "\n\n" ++ received_line;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{});
+ return .zero;
+ }
+ globalObject.throw(Output.prettyFmt(fmt, false), .{});
+ return .zero;
+ }
+
+ if (expected_value.isString()) {
+ const expected_fmt = "\n\nExpected substring: <green>{any}<r>\n\n" ++ received_line;
+ const fmt = signature ++ expected_fmt;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{expected_value.toFmt(globalObject, &formatter)});
+ return .zero;
+ }
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{expected_value.toFmt(globalObject, &formatter)});
+ return .zero;
+ }
+
+ if (expected_value.get(globalObject, "message")) |expected_message| {
+ const expected_fmt = "\n\nExpected message: <green>{any}<r>\n\n" ++ received_line;
+ const fmt = signature ++ expected_fmt;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{expected_message.toFmt(globalObject, &formatter)});
+ return .zero;
+ }
+
+ globalObject.throw(Output.prettyFmt(fmt, false), .{expected_message.toFmt(globalObject, &formatter)});
+ return .zero;
+ }
+
+ const expected_fmt = "\n\nExpected constructor: <green>{s}<r>\n\n" ++ received_line;
+ var expected_class = ZigString.Empty;
+ expected_value.getClassName(globalObject, &expected_class);
+ const fmt = signature ++ expected_fmt;
+ if (Output.enable_ansi_colors) {
+ globalObject.throw(Output.prettyFmt(fmt, true), .{expected_class});
+ return .zero;
+ }
+ globalObject.throw(Output.prettyFmt(fmt, true), .{expected_class});
return .zero;
}