aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alex Lam S.L <alexlamsl@gmail.com> 2023-01-05 08:37:14 +0200
committerGravatar GitHub <noreply@github.com> 2023-01-04 22:37:14 -0800
commit80736043d64941bafe8a9c42431ade4ad77d57e3 (patch)
treeb4dbae90f6c720f1d530e3c53f95a8b620e60baf
parent3b259211df10e06ddf5844898a6ffa3c9679e4d8 (diff)
downloadbun-80736043d64941bafe8a9c42431ade4ad77d57e3.tar.gz
bun-80736043d64941bafe8a9c42431ade4ad77d57e3.tar.zst
bun-80736043d64941bafe8a9c42431ade4ad77d57e3.zip
implement `expect().toThrow()` (#1727)
- fix bugs in `JSBufferList` - add tests
-rw-r--r--packages/bun-types/bun-test.d.ts1
-rw-r--r--src/bun.js/bindings/JSBufferList.cpp58
-rw-r--r--src/bun.js/test/jest.zig82
-rw-r--r--test/bun.js/bufferlist.test.ts187
-rw-r--r--test/bun.js/websocket-server.test.ts172
5 files changed, 370 insertions, 130 deletions
diff --git a/packages/bun-types/bun-test.d.ts b/packages/bun-types/bun-test.d.ts
index 7567c5ad2..1c14f8769 100644
--- a/packages/bun-types/bun-test.d.ts
+++ b/packages/bun-types/bun-test.d.ts
@@ -50,6 +50,7 @@ declare module "bun:test" {
toBeGreaterThanOrEqual(value: number | bigint): void;
toBeLessThan(value: number | bigint): void;
toBeLessThanOrEqual(value: number | bigint): void;
+ toThrow(message: string | ErrorConstructor): void;
}
}
diff --git a/src/bun.js/bindings/JSBufferList.cpp b/src/bun.js/bindings/JSBufferList.cpp
index e16c8cf88..e54b433e5 100644
--- a/src/bun.js/bindings/JSBufferList.cpp
+++ b/src/bun.js/bindings/JSBufferList.cpp
@@ -2,7 +2,6 @@
#include "JSBuffer.h"
#include "JavaScriptCore/Lookup.h"
#include "JavaScriptCore/ObjectConstructor.h"
-#include "JavaScriptCore/JSGenericTypedArrayViewInlines.h"
#include "ZigGlobalObject.h"
#include "JSDOMOperation.h"
#include "headers.h"
@@ -48,6 +47,9 @@ JSC::JSValue JSBufferList::concat(JSC::VM& vm, JSC::JSGlobalObject* lexicalGloba
if (UNLIKELY(!array)) {
return throwTypeError(lexicalGlobalObject, throwScope, "concat can only be called when all buffers are Uint8Array"_s);
}
+ if (UNLIKELY(array->byteLength() > n)) {
+ return throwRangeError(lexicalGlobalObject, throwScope, "specified size too small to fit all buffers"_s);
+ }
RELEASE_AND_RETURN(throwScope, array);
}
// Buffer.allocUnsafe(n >>> 0)
@@ -106,10 +108,10 @@ JSC::JSValue JSBufferList::consume(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlob
return _getBuffer(vm, lexicalGlobalObject, n);
}
-JSC::JSValue JSBufferList::_getString(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, int32_t n)
+JSC::JSValue JSBufferList::_getString(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, int32_t total)
{
auto throwScope = DECLARE_THROW_SCOPE(vm);
- if (n == 0 || length() == 0) {
+ if (total <= 0 || length() == 0) {
RELEASE_AND_RETURN(throwScope, JSC::jsEmptyString(vm));
}
@@ -118,7 +120,8 @@ JSC::JSValue JSBufferList::_getString(JSC::VM& vm, JSC::JSGlobalObject* lexicalG
if (UNLIKELY(!str)) {
return throwTypeError(lexicalGlobalObject, throwScope, "_getString can only be called when all buffers are string"_s);
}
- size_t len = str->length();
+ const size_t len = str->length();
+ size_t n = total;
if (n == len) {
m_deque.removeFirst();
@@ -131,32 +134,33 @@ JSC::JSValue JSBufferList::_getString(JSC::VM& vm, JSC::JSGlobalObject* lexicalG
}
JSRopeString::RopeBuilder<RecordOverflow> ropeBuilder(vm);
- for (const auto end = m_deque.end(); iter != end && n > 0; ++iter) {
+ for (const auto end = m_deque.end(); iter != end; ++iter) {
JSC::JSString* str = JSC::jsDynamicCast<JSC::JSString*>(iter->get());
if (UNLIKELY(!str)) {
return throwTypeError(lexicalGlobalObject, throwScope, "_getString can only be called when all buffers are string"_s);
}
- size_t len = str->length();
+ const size_t len = str->length();
if (n < len) {
JSString* firstHalf = JSC::jsSubstring(lexicalGlobalObject, str, 0, n);
if (!ropeBuilder.append(firstHalf))
return throwOutOfMemoryError(lexicalGlobalObject, throwScope);
iter->set(vm, this, JSC::jsSubstring(lexicalGlobalObject, str, n, len - n));
- } else {
- if (!ropeBuilder.append(str))
- return throwOutOfMemoryError(lexicalGlobalObject, throwScope);
- m_deque.removeFirst();
+ break;
}
- n -= static_cast<int32_t>(len);
+ if (!ropeBuilder.append(str))
+ return throwOutOfMemoryError(lexicalGlobalObject, throwScope);
+ m_deque.removeFirst();
+ if (n == len) break;
+ n -= len;
}
RELEASE_AND_RETURN(throwScope, ropeBuilder.release());
}
-JSC::JSValue JSBufferList::_getBuffer(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, int32_t n)
+JSC::JSValue JSBufferList::_getBuffer(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, int32_t total)
{
auto throwScope = DECLARE_THROW_SCOPE(vm);
auto* subclassStructure = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject)->JSBufferSubclassStructure();
- if (n == 0 || length() == 0) {
+ if (total <= 0 || length() == 0) {
// Buffer.alloc(0)
RELEASE_AND_RETURN(throwScope, JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, 0));
}
@@ -166,13 +170,15 @@ JSC::JSValue JSBufferList::_getBuffer(JSC::VM& vm, JSC::JSGlobalObject* lexicalG
if (UNLIKELY(!array)) {
return throwTypeError(lexicalGlobalObject, throwScope, "_getBuffer can only be called when all buffers are Uint8Array"_s);
}
- size_t len = array->byteLength();
+ const size_t len = array->byteLength();
+ size_t n = total;
if (n == len) {
+ m_deque.removeFirst();
RELEASE_AND_RETURN(throwScope, array);
}
if (n < len) {
- auto buffer = array->existingBuffer();
+ auto buffer = array->possiblySharedBuffer();
JSC::JSUint8Array* retArray = JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, buffer, 0, n);
JSC::JSUint8Array* newArray = JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, buffer, n, len - n);
iter->set(vm, this, newArray);
@@ -182,29 +188,31 @@ JSC::JSValue JSBufferList::_getBuffer(JSC::VM& vm, JSC::JSGlobalObject* lexicalG
// Buffer.allocUnsafe(n >>> 0)
auto arrayBuffer = JSC::ArrayBuffer::tryCreateUninitialized(n, 1);
if (UNLIKELY(!arrayBuffer)) {
- return throwTypeError(lexicalGlobalObject, throwScope);
+ return throwOutOfMemoryError(lexicalGlobalObject, throwScope);
}
JSC::JSUint8Array* uint8Array = JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, WTFMove(arrayBuffer), 0, n);
size_t offset = 0;
- for (const auto end = m_deque.end(); iter != end && n > 0; ++iter) {
+ for (const auto end = m_deque.end(); iter != end; ++iter) {
JSC::JSUint8Array* array = JSC::jsDynamicCast<JSC::JSUint8Array*>(iter->get());
if (UNLIKELY(!array)) {
return throwTypeError(lexicalGlobalObject, throwScope, "_getBuffer can only be called when all buffers are Uint8Array"_s);
}
- size_t len = array->byteLength();
+ const size_t len = array->byteLength();
if (n < len) {
if (UNLIKELY(!uint8Array->setFromTypedArray(lexicalGlobalObject, offset, array, 0, n, JSC::CopyType::Unobservable))) {
return throwOutOfMemoryError(lexicalGlobalObject, throwScope);
}
- JSC::JSUint8Array* newArray = JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, array->existingBuffer(), n, len - n);
+ auto buffer = array->possiblySharedBuffer();
+ JSC::JSUint8Array* newArray = JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, buffer, n, len - n);
iter->set(vm, this, newArray);
- } else {
- if (UNLIKELY(!uint8Array->setFromTypedArray(lexicalGlobalObject, offset, array, 0, len, JSC::CopyType::Unobservable))) {
- return throwOutOfMemoryError(lexicalGlobalObject, throwScope);
- }
- m_deque.removeFirst();
+ break;
+ }
+ if (UNLIKELY(!uint8Array->setFromTypedArray(lexicalGlobalObject, offset, array, 0, len, JSC::CopyType::Unobservable))) {
+ return throwOutOfMemoryError(lexicalGlobalObject, throwScope);
}
- n -= static_cast<int32_t>(len);
+ m_deque.removeFirst();
+ if (n == len) break;
+ n -= len;
offset += len;
}
RELEASE_AND_RETURN(throwScope, uint8Array);
diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig
index 24c1bd0e1..ba9234c6d 100644
--- a/src/bun.js/test/jest.zig
+++ b/src/bun.js/test/jest.zig
@@ -535,7 +535,7 @@ pub const Expect = struct {
defer this.postMatch(globalObject);
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!", .{});
+ globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
return .zero;
};
value.ensureStillAlive();
@@ -564,7 +564,7 @@ pub const Expect = struct {
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!", .{});
+ globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
return .zero;
};
value.ensureStillAlive();
@@ -596,7 +596,7 @@ pub const Expect = struct {
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!", .{});
+ globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
return .zero;
};
value.ensureStillAlive();
@@ -623,7 +623,7 @@ pub const Expect = struct {
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!", .{});
+ globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
return .zero;
};
value.ensureStillAlive();
@@ -851,7 +851,7 @@ pub const Expect = struct {
other_value.ensureStillAlive();
const value = Expect.capturedValueGetCached(thisValue) orelse {
- globalObject.throw("Internal consistency error: thie expect(value) was garbage collected but it should not have been!", .{});
+ globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
return .zero;
};
value.ensureStillAlive();
@@ -914,7 +914,7 @@ pub const Expect = struct {
other_value.ensureStillAlive();
const value = Expect.capturedValueGetCached(thisValue) orelse {
- globalObject.throw("Internal consistency error: thie expect(value) was garbage collected but it should not have been!", .{});
+ globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
return .zero;
};
value.ensureStillAlive();
@@ -977,7 +977,7 @@ pub const Expect = struct {
other_value.ensureStillAlive();
const value = Expect.capturedValueGetCached(thisValue) orelse {
- globalObject.throw("Internal consistency error: thie expect(value) was garbage collected but it should not have been!", .{});
+ globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
return .zero;
};
value.ensureStillAlive();
@@ -1040,7 +1040,7 @@ pub const Expect = struct {
other_value.ensureStillAlive();
const value = Expect.capturedValueGetCached(thisValue) orelse {
- globalObject.throw("Internal consistency error: thie expect(value) was garbage collected but it should not have been!", .{});
+ globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
return .zero;
};
value.ensureStillAlive();
@@ -1080,6 +1080,71 @@ pub const Expect = struct {
return .zero;
}
+ pub fn toThrow(this: *Expect, globalObject: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSValue {
+ defer this.postMatch(globalObject);
+
+ const thisValue = callFrame.this();
+ const _arguments = callFrame.arguments(1);
+ const arguments: []const JSValue = _arguments.ptr[0.._arguments.len];
+
+ if (arguments.len < 1) {
+ globalObject.throwInvalidArguments("toThrow() requires 1 argument", .{});
+ return .zero;
+ }
+
+ if (this.scope.tests.items.len <= this.test_id) {
+ globalObject.throw("toThrow() must be called in a test", .{});
+ return .zero;
+ }
+
+ active_test_expectation_counter.actual += 1;
+
+ const expected = arguments[0];
+ expected.ensureStillAlive();
+
+ const value = 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 ((!value.jsType().isFunction())) {
+ globalObject.throw("Expected value must be a function", .{});
+ return .zero;
+ }
+
+ const not = this.op.contains(.not);
+ const result = value.call(globalObject, &.{}).toError(globalObject);
+ if (result.isUndefined()) {
+ if (not) return thisValue;
+ globalObject.throw("Expected function to throw", .{});
+ return .zero;
+ } else if(not) {
+ globalObject.throw("Expected function not to throw", .{});
+ return .zero;
+ }
+
+ if (expected.isString()) {
+ const message = result.get(globalObject, "message");
+ // TODO support partial match
+ const pass = if (message) |actual| expected.isSameValue(actual, globalObject) else false;
+
+ if (pass) return thisValue;
+ globalObject.throw("\n\tExpected: {s}\n\tReceived: {s}", .{
+ expected.getZigString(globalObject),
+ if (message) |actual| actual.getZigString(globalObject) else ZigString.init("undefined"),
+ });
+ return .zero;
+ }
+
+ if (result.isInstanceOf(globalObject, expected)) return thisValue;
+ globalObject.throw("\n\tExpected type: {s}\n\tReceived type: {s}", .{
+ expected.getName(globalObject),
+ if (result.get(globalObject, "name")) |name| name.getZigString(globalObject) else ZigString.init("<UnknownError>"),
+ });
+ return .zero;
+ }
+
pub const toHaveBeenCalledTimes = notImplementedJSCFn;
pub const toHaveBeenCalledWith = notImplementedJSCFn;
pub const toHaveBeenLastCalledWith = notImplementedJSCFn;
@@ -1095,7 +1160,6 @@ pub const Expect = struct {
pub const toMatchObject = notImplementedJSCFn;
pub const toMatchSnapshot = notImplementedJSCFn;
pub const toMatchInlineSnapshot = notImplementedJSCFn;
- pub const toThrow = notImplementedJSCFn;
pub const toThrowErrorMatchingSnapshot = notImplementedJSCFn;
pub const toThrowErrorMatchingInlineSnapshot = notImplementedJSCFn;
diff --git a/test/bun.js/bufferlist.test.ts b/test/bun.js/bufferlist.test.ts
new file mode 100644
index 000000000..e344d49b4
--- /dev/null
+++ b/test/bun.js/bufferlist.test.ts
@@ -0,0 +1,187 @@
+import { Readable } from "stream";
+import { it, expect } from "bun:test";
+
+function makeUint8Array(str) {
+ return new Uint8Array([].map.call(str, function(ch) {
+ return ch.charCodeAt(0);
+ }));
+}
+
+it("should work with .clear()", () => {
+ const list = new Readable().readableBuffer;
+ expect(list.length).toBe(0);
+ expect(list.push({})).toBeUndefined();
+ expect(list.length).toBe(1);
+ expect(list.push({})).toBeUndefined();
+ expect(list.length).toBe(2);
+ expect(list.clear()).toBeUndefined();
+ expect(list.length).toBe(0);
+});
+
+it("should work with .concat()", () => {
+ const list = new Readable().readableBuffer;
+ expect(list.length).toBe(0);
+ expect(list.push(makeUint8Array("foo"))).toBeUndefined();
+ expect(list.length).toBe(1);
+ expect(list.concat(3)).toEqual(new Uint8Array([ 102, 111, 111 ]));
+ expect(list.push(makeUint8Array("bar"))).toBeUndefined();
+ expect(list.length).toBe(2);
+ expect(list.concat(10)).toEqual(new Uint8Array([
+ 102, 111, 111, 98, 97,
+ 114, 0, 0, 0, 0,
+ ]));
+});
+
+it("should fail on .concat() with invalid items", () => {
+ const list = new Readable().readableBuffer;
+ expect(list.length).toBe(0);
+ expect(list.push("foo")).toBeUndefined();
+ expect(() => {
+ list.concat(42);
+ }).toThrow(TypeError);
+});
+
+it("should fail on .concat() buffer overflow", () => {
+ const list = new Readable().readableBuffer;
+ expect(list.length).toBe(0);
+ expect(list.push(makeUint8Array("foo"))).toBeUndefined();
+ expect(list.length).toBe(1);
+ expect(() => {
+ list.concat(2);
+ }).toThrow(RangeError);
+ expect(list.push(makeUint8Array("bar"))).toBeUndefined();
+ expect(list.length).toBe(2);
+ expect(() => {
+ list.concat(5);
+ }).toThrow(RangeError);
+});
+
+it("should work with .consume() on strings", () => {
+ const list = new Readable().readableBuffer;
+ expect(list.length).toBe(0);
+ expect(list.consume(42, true)).toBe("");
+ expect(list.push("foo")).toBeUndefined();
+ expect(list.push("bar")).toBeUndefined();
+ expect(list.push("baz")).toBeUndefined();
+ expect(list.push("moo")).toBeUndefined();
+ expect(list.push("moz")).toBeUndefined();
+ expect(list.length).toBe(5);
+ expect(list.consume(3, true)).toBe("foo");
+ expect(list.length).toBe(4);
+ expect(list.consume(4, true)).toBe("barb");
+ expect(list.length).toBe(3);
+ expect(list.consume(256, true)).toBe("azmoomoz");
+ expect(list.length).toBe(0);
+});
+
+it("should work with .consume() on buffers", () => {
+ const list = new Readable().readableBuffer;
+ expect(list.length).toBe(0);
+ expect(list.consume(42, false)).toEqual(new Uint8Array());
+ expect(list.push(makeUint8Array("foo"))).toBeUndefined();
+ expect(list.push(makeUint8Array("bar"))).toBeUndefined();
+ expect(list.push(makeUint8Array("baz"))).toBeUndefined();
+ expect(list.push(makeUint8Array("moo"))).toBeUndefined();
+ expect(list.push(makeUint8Array("moz"))).toBeUndefined();
+ expect(list.length).toBe(5);
+ expect(list.consume(3, false)).toEqual(makeUint8Array("foo"));
+ expect(list.length).toBe(4);
+ expect(list.consume(2, false)).toEqual(makeUint8Array("ba"));
+ expect(list.length).toBe(4);
+ expect(list.consume(4, false)).toEqual(makeUint8Array("rbaz"));
+ expect(list.length).toBe(2);
+ expect(list.consume(10, false)).toEqual(new Uint8Array([
+ 109, 111, 111, 109, 111,
+ 122, 0, 0, 0, 0,
+ ]));
+ expect(list.length).toBe(0);
+});
+
+it("should fail on .consume() with invalid items", () => {
+ const list = new Readable().readableBuffer;
+ expect(list.length).toBe(0);
+ expect(list.push("foo")).toBeUndefined();
+ expect(list.length).toBe(1);
+ expect(list.consume(0, false)).toEqual(new Uint8Array([]));
+ expect(() => {
+ list.consume(1, false);
+ }).toThrow(TypeError);
+ expect(list.consume(3, true)).toBe("foo");
+ expect(list.length).toBe(0);
+ expect(list.push(makeUint8Array("bar"))).toBeUndefined();
+ expect(list.length).toBe(1);
+ expect(list.consume(0, true)).toEqual("");
+ expect(() => {
+ list.consume(1, true);
+ }).toThrow(TypeError);
+ expect(list.consume(3, false)).toEqual(new Uint8Array([ 98, 97, 114 ]));
+});
+
+it("should work with .first()", () => {
+ const list = new Readable().readableBuffer;
+ expect(list.length).toBe(0);
+ expect(list.first()).toBeUndefined();
+ const item = {};
+ expect(list.push(item)).toBeUndefined();
+ expect(list.length).toBe(1);
+ expect(list.first()).toBe(item);
+});
+
+it("should work with .join()", () => {
+ const list = new Readable().readableBuffer;
+ expect(list.length).toBe(0);
+ expect(list.push(42)).toBeUndefined();
+ expect(list.push(null)).toBeUndefined();
+ expect(list.push("foo")).toBeUndefined();
+ expect(list.push(makeUint8Array("bar"))).toBeUndefined();
+ expect(list.length).toBe(4);
+ expect(list.join("")).toBe("42nullfoo98,97,114");
+ expect(list.join(",")).toBe("42,null,foo,98,97,114");
+ expect(list.join(" baz ")).toBe("42 baz null baz foo baz 98,97,114");
+});
+
+it("should work with .push()", () => {
+ const list = new Readable().readableBuffer;
+ expect(list.length).toBe(0);
+ const item1 = {};
+ expect(list.push(item1)).toBeUndefined();
+ expect(list.length).toBe(1);
+ expect(list.first()).toBe(item1);
+ const item2 = {};
+ expect(list.push(item2)).toBeUndefined();
+ expect(list.length).toBe(2);
+ expect(list.shift()).toBe(item1);
+ expect(list.shift()).toBe(item2);
+ expect(list.shift()).toBeUndefined();
+});
+
+it("should work with .shift()", () => {
+ const list = new Readable().readableBuffer;
+ expect(list.length).toBe(0);
+ expect(list.shift()).toBeUndefined();
+ const item = {};
+ expect(list.push(item)).toBeUndefined();
+ expect(list.length).toBe(1);
+ expect(list.shift()).toBe(item);
+ expect(list.shift()).toBeUndefined();
+});
+
+it("should work with .unshift()", () => {
+ const list = new Readable().readableBuffer;
+ expect(list.length).toBe(0);
+ const item1 = {};
+ expect(list.unshift(item1)).toBeUndefined();
+ expect(list.length).toBe(1);
+ expect(list.first()).toBe(item1);
+ const item2 = {};
+ expect(list.push(item2)).toBeUndefined();
+ expect(list.length).toBe(2);
+ expect(list.first()).toBe(item1);
+ const item3 = {};
+ expect(list.unshift(item3)).toBeUndefined();
+ expect(list.length).toBe(3);
+ expect(list.shift()).toBe(item3);
+ expect(list.shift()).toBe(item1);
+ expect(list.shift()).toBe(item2);
+ expect(list.shift()).toBeUndefined();
+});
diff --git a/test/bun.js/websocket-server.test.ts b/test/bun.js/websocket-server.test.ts
index 949b1fc6e..1d9c15341 100644
--- a/test/bun.js/websocket-server.test.ts
+++ b/test/bun.js/websocket-server.test.ts
@@ -104,7 +104,6 @@ describe("websocket server", () => {
});
second.close();
- } catch (r) {
} finally {
server.stop();
}
@@ -157,59 +156,58 @@ describe("websocket server", () => {
});
it("headers error doesn't crash", async () => {
- var resolve, reject;
- var server = serve({
- port: getPort(),
- websocket: {
- open(ws) {},
- message(ws, msg) {},
- close() {
+ await new Promise<void>((resolve, reject) => {
+ const server = serve({
+ port: getPort(),
+ websocket: {
+ open(ws) {
+ server.stop();
+ },
+ message(ws, msg) {},
+ close() {
+ resolve();
+ },
+ },
+ error(err) {
resolve();
},
- },
- error(err) {
- resolve();
- },
- fetch(req, server) {
- try {
- if (
- server.upgrade(req, {
- data: "hello world",
- headers: 1238 as any,
- })
- ) {
- reject(new Error("should not upgrade"));
- return;
- }
- } catch (e) {
+ fetch(req, server) {
+ server.stop();
+ expect(() => {
+ if (
+ server.upgrade(req, {
+ data: "hello world",
+ headers: 1238 as any,
+ })
+ ) {
+ reject(new Error("should not upgrade"));
+ return new Response("should not upgrade");
+ }
+ }).toThrow("upgrade options.headers must be a Headers or an object");
resolve();
return new Response("success");
- }
-
- reject(new Error("should throw error"));
- return new Response("noooooo hello world");
- },
- });
+ },
+ });
- await new Promise<void>((resolve_, reject) => {
- resolve = resolve_;
const websocket = new WebSocket(`ws://${server.hostname}:${server.port}`);
websocket.onopen = () => websocket.close();
websocket.onmessage = (e) => {};
websocket.onerror = (e) => {};
});
- server.stop();
});
it("can do hello world", async () => {
- var server = serve({
+ const server = serve({
port: getPort(),
websocket: {
- open(ws) {},
+ open(ws) {
+ server.stop();
+ },
message(ws, msg) {
ws.send("hello world");
},
},
fetch(req, server) {
+ server.stop();
if (
server.upgrade(req, {
data: "hello world",
@@ -241,9 +239,7 @@ describe("websocket server", () => {
resolve();
} catch (r) {
reject(r);
- return;
} finally {
- server?.stop();
websocket.close();
}
};
@@ -251,14 +247,15 @@ describe("websocket server", () => {
reject(e);
};
});
- server.stop();
});
it("fetch() allows a Response object to be returned for an upgraded ServerWebSocket", () => {
- var server = serve({
+ const server = serve({
port: getPort(),
websocket: {
- open(ws) {},
+ open(ws) {
+ server.stop();
+ },
message(ws, msg) {
ws.send("hello world");
},
@@ -267,6 +264,7 @@ describe("websocket server", () => {
console.error(err);
},
fetch(req, server) {
+ server.stop();
if (
server.upgrade(req, {
data: "hello world",
@@ -300,9 +298,7 @@ describe("websocket server", () => {
resolve();
} catch (r) {
reject(r);
- return;
} finally {
- server?.stop();
websocket.close();
}
};
@@ -313,10 +309,12 @@ describe("websocket server", () => {
});
it("fetch() allows a Promise<Response> object to be returned for an upgraded ServerWebSocket", () => {
- var server = serve({
+ const server = serve({
port: getPort(),
websocket: {
- async open(ws) {},
+ async open(ws) {
+ server.stop();
+ },
async message(ws, msg) {
await 1;
ws.send("hello world");
@@ -326,6 +324,7 @@ describe("websocket server", () => {
console.error(err);
},
async fetch(req, server) {
+ server.stop();
await 1;
if (
server.upgrade(req, {
@@ -359,9 +358,7 @@ describe("websocket server", () => {
resolve();
} catch (r) {
reject(r);
- return;
} finally {
- server?.stop();
websocket.close();
}
};
@@ -372,10 +369,12 @@ describe("websocket server", () => {
});
it("binaryType works", async () => {
var done = false;
- var server = serve({
+ const server = serve({
port: getPort(),
websocket: {
- open(ws) {},
+ open(ws) {
+ server.stop();
+ },
message(ws, msg) {
if (ws.binaryType === "uint8array") {
expect(ws.binaryType).toBe("uint8array");
@@ -392,6 +391,7 @@ describe("websocket server", () => {
},
},
fetch(req, server) {
+ server.stop();
if (server.upgrade(req, { data: "hello world" })) {
if (server.upgrade(req)) {
throw new Error("should not upgrade twice");
@@ -414,24 +414,19 @@ describe("websocket server", () => {
expect(e.data).toBe("hello world");
if (counter++ > 0) {
- server?.stop();
websocket.close();
resolve(done);
}
websocket.send(Buffer.from("oaksd"));
} catch (r) {
- server?.stop();
websocket.close();
reject(r);
- return;
- } finally {
}
};
websocket.onerror = (e) => {
reject(e);
};
});
- server.stop();
});
it("does not upgrade for non-websocket connections", async () => {
@@ -462,38 +457,35 @@ describe("websocket server", () => {
it("does not upgrade for non-websocket servers", async () => {
await new Promise<void>(async (resolve, reject) => {
- var server = serve({
+ const server = serve({
port: getPort(),
-
fetch(req, server) {
- try {
+ server.stop();
+ expect(() => {
server.upgrade(req);
- reject(new Error("should not upgrade"));
- } catch (e) {
- return new Response("success");
- }
-
- return new Response("fail");
+ }).toThrow('To enable websocket support, set the "websocket" object in Bun.serve({})');
+ return new Response("success");
},
});
const response = await fetch(`http://${server.hostname}:${server.port}`);
expect(await response.text()).toBe("success");
resolve();
- server.stop();
});
});
it("async can do hello world", async () => {
- var server = serve({
+ const server = serve({
port: getPort(),
websocket: {
async open(ws) {
+ server.stop();
ws.send("hello world");
},
message(ws, msg) {},
},
async fetch(req, server) {
+ server.stop();
await 1;
if (server.upgrade(req)) return;
@@ -510,9 +502,7 @@ describe("websocket server", () => {
resolve();
} catch (r) {
reject(r);
- return;
} finally {
- server?.stop();
websocket.close();
}
};
@@ -633,10 +623,11 @@ describe("websocket server", () => {
});
it("can do hello world corked", async () => {
- var server = serve({
+ const server = serve({
port: getPort(),
websocket: {
open(ws) {
+ server.stop();
ws.send("hello world");
},
message(ws, msg) {
@@ -646,8 +637,8 @@ describe("websocket server", () => {
},
},
fetch(req, server) {
+ server.stop();
if (server.upgrade(req)) return;
-
return new Response("noooooo hello world");
},
});
@@ -661,9 +652,7 @@ describe("websocket server", () => {
resolve();
} catch (r) {
reject(r);
- return;
} finally {
- server?.stop();
websocket.close();
}
};
@@ -675,10 +664,12 @@ describe("websocket server", () => {
it("can do some back and forth", async () => {
var dataCount = 0;
- var server = serve({
+ const server = serve({
port: getPort(),
websocket: {
- open(ws) {},
+ open(ws) {
+ server.stop();
+ },
message(ws, msg) {
if (msg === "first") {
ws.send("first");
@@ -688,6 +679,7 @@ describe("websocket server", () => {
},
},
fetch(req, server) {
+ server.stop();
if (
server.upgrade(req, {
data: { count: 0 },
@@ -731,12 +723,7 @@ describe("websocket server", () => {
}
} catch (r) {
reject(r);
- console.error(r);
- server?.stop();
- console.log("i am closing!");
websocket.close();
- return;
- } finally {
}
};
});
@@ -752,16 +739,19 @@ describe("websocket server", () => {
var serverCounter = 0;
var clientCounter = 0;
- var server = serve({
+ const server = serve({
port: getPort(),
websocket: {
- open(ws) {},
+ open(ws) {
+ server.stop();
+ },
message(ws, msg) {
ws.send(sendQueue[serverCounter++] + " ");
gcTick();
},
},
fetch(req, server) {
+ server.stop();
if (
server.upgrade(req, {
data: { count: 0 },
@@ -793,15 +783,10 @@ describe("websocket server", () => {
} catch (r) {
reject(r);
console.error(r);
- server?.stop();
websocket.close();
- return;
- } finally {
}
};
});
-
- server?.stop();
});
// this test sends 100 messages to 10 connected clients via pubsub
@@ -814,10 +799,11 @@ describe("websocket server", () => {
}
var serverCounter = 0;
var clientCount = 0;
- var server = serve({
+ const server = serve({
port: getPort(),
websocket: {
open(ws) {
+ server.stop();
ws.subscribe("test");
gcTick();
if (!ws.isSubscribed("test")) {
@@ -837,14 +823,12 @@ describe("websocket server", () => {
ws.publish("test", sendQueue[serverCounter++] + " ");
},
},
- fetch(req, server) {
+ fetch(req) {
gcTick();
-
- if (
- server.upgrade(req, {
- data: { count: 0 },
- })
- )
+ server.stop();
+ if (server.upgrade(req, {
+ data: { count: 0 },
+ }))
return;
return new Response("noooooo hello world");
},
@@ -922,17 +906,13 @@ describe("websocket server", () => {
}
} catch (r) {
console.error(r);
- server?.stop();
websocket.close();
rejectConnection(r);
gcTick();
- return;
- } finally {
}
};
}
});
- server?.stop();
expect(serverCounter).toBe(sendQueue.length);
});
});