aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alex Lam S.L <alexlamsl@gmail.com> 2023-03-06 03:33:38 +0200
committerGravatar GitHub <noreply@github.com> 2023-03-06 03:33:38 +0200
commitd4bd156d9d3bebbf447e84183d4b49dea0b531cd (patch)
tree81a20e93fc3788c2a47e02786359ae4e32aed644
parentc7bfb3aa3acdd1c8b11782530110aaf417cb79b8 (diff)
downloadbun-d4bd156d9d3bebbf447e84183d4b49dea0b531cd.tar.gz
bun-d4bd156d9d3bebbf447e84183d4b49dea0b531cd.tar.zst
bun-d4bd156d9d3bebbf447e84183d4b49dea0b531cd.zip
support `expect().toThrow(/pattern/)` (#2314)
- fix time-zone-dependent test failure
-rw-r--r--packages/bun-types/bun-test.d.ts2
-rw-r--r--src/bun.js/test/jest.zig77
-rw-r--r--test/bun.js/console/console-log.expected.txt2
-rw-r--r--test/bun.js/console/console-log.js2
-rw-r--r--test/bun.js/crypto-scrypt.test.js99
-rw-r--r--test/bun.js/test-test.test.ts13
6 files changed, 124 insertions, 71 deletions
diff --git a/packages/bun-types/bun-test.d.ts b/packages/bun-types/bun-test.d.ts
index 5e3adf041..1b7ae47a6 100644
--- a/packages/bun-types/bun-test.d.ts
+++ b/packages/bun-types/bun-test.d.ts
@@ -76,7 +76,7 @@ declare module "bun:test" {
toBeGreaterThanOrEqual(value: number | bigint): void;
toBeLessThan(value: number | bigint): void;
toBeLessThanOrEqual(value: number | bigint): void;
- toThrow(error?: string | Error | ErrorConstructor): void;
+ toThrow(error?: string | Error | ErrorConstructor | RegExp): void;
}
}
diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig
index 20e11e132..5571294c7 100644
--- a/src/bun.js/test/jest.zig
+++ b/src/bun.js/test/jest.zig
@@ -1768,7 +1768,7 @@ pub const Expect = struct {
if (expected_value.isString()) {
const received_message = result.getIfPropertyExistsImpl(globalObject, "message", 7);
- // partial match (regex not supported)
+ // partial match
{
var expected_string = ZigString.Empty;
var received_string = ZigString.Empty;
@@ -1798,6 +1798,29 @@ pub const Expect = struct {
return .zero;
}
+ if (expected_value.isRegExp()) {
+ const received_message = result.getIfPropertyExistsImpl(globalObject, "message", 7);
+
+ if (expected_value.get(globalObject, "test")) |test_fn| {
+ const matches = test_fn.callWithThis(globalObject, expected_value, &.{received_message});
+ if (!matches.toBooleanSlow(globalObject)) return thisValue;
+ }
+
+ const fmt = signature ++ "\n\nExpected pattern: 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
@@ -1835,7 +1858,7 @@ pub const Expect = struct {
if (expected_value.isString()) {
if (_received_message) |received_message| {
- // partial match (regex not supported)
+ // partial match
var expected_string = ZigString.Empty;
var received_string = ZigString.Empty;
expected_value.toZigString(&expected_string, globalObject);
@@ -1877,6 +1900,42 @@ pub const Expect = struct {
return .zero;
}
+ if (expected_value.isRegExp()) {
+ if (_received_message) |received_message| {
+ if (expected_value.get(globalObject, "test")) |test_fn| {
+ const matches = test_fn.callWithThis(globalObject, expected_value, &.{received_message});
+ if (matches.toBooleanSlow(globalObject)) return thisValue;
+ }
+ }
+
+ // error: message from received error does not match expected pattern
+ var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject, .quote_strings = true };
+
+ 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 pattern: <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;
+ }
+
+ 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 pattern: <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;
@@ -1985,6 +2044,18 @@ pub const Expect = struct {
return .zero;
}
+ if (expected_value.isRegExp()) {
+ const expected_fmt = "\n\nExpected pattern: <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;
@@ -2275,7 +2346,7 @@ pub const TestScope = struct {
task,
);
task.done_callback_state = .pending;
- initial_value = JSValue.fromRef(callback.?).call(vm.global, &.{callback_func});
+ initial_value = JSValue.fromRef(callback).call(vm.global, &.{callback_func});
} else {
initial_value = js.JSObjectCallAsFunctionReturnValue(vm.global, callback, null, 0, null);
}
diff --git a/test/bun.js/console/console-log.expected.txt b/test/bun.js/console/console-log.expected.txt
index 69fb3eeba..97191c8be 100644
--- a/test/bun.js/console/console-log.expected.txt
+++ b/test/bun.js/console/console-log.expected.txt
@@ -8,7 +8,7 @@ false
null
undefined
Symbol(Symbol Description)
-2022-02-27T05:11:48.999Z
+2000-06-27T02:24:34.304Z
[ 123, 456, 789 ]
{
name: "foo"
diff --git a/test/bun.js/console/console-log.js b/test/bun.js/console/console-log.js
index 5468c1c98..e23a3e9cb 100644
--- a/test/bun.js/console/console-log.js
+++ b/test/bun.js/console/console-log.js
@@ -8,7 +8,7 @@ console.log(false);
console.log(null);
console.log(undefined);
console.log(Symbol("Symbol Description"));
-console.log(new Date(2021, 12, 30, 666, 777, 888, 999));
+console.log(new Date(Math.pow(2, 34) * 56));
console.log([123, 456, 789]);
console.log({ name: "foo" });
console.log({ a: 123, b: 456, c: 789 });
diff --git a/test/bun.js/crypto-scrypt.test.js b/test/bun.js/crypto-scrypt.test.js
index e188e9fae..4b7412251 100644
--- a/test/bun.js/crypto-scrypt.test.js
+++ b/test/bun.js/crypto-scrypt.test.js
@@ -3,35 +3,6 @@
import { expect, it } from "bun:test";
const crypto = require("crypto");
-const assert = {
- strictEqual: (a, b) => {
- expect(a).toEqual(b);
- },
- deepStrictEqual: (a, b) => {
- expect(a).toEqual(b);
- },
- throws: (fn, err) => {
- try {
- fn();
- throw "Fail";
- } catch (e) {
- if (err.name) {
- expect(e?.name).toEqual(err.name);
- }
-
- // if (err.message) {
- // expect(err.message.test(e?.message)).toBeTruthy();
- // }
- if (err.code) {
- expect(e?.code).toEqual(err.code);
- }
-
- expect(e).not.toEqual("Fail");
- return;
- }
- },
-};
-
const good = [
// Zero-length key is legal, functions as a parameter validation check.
{
@@ -157,8 +128,24 @@ const badargs = [
args: ["", "", null],
expected: { code: "ERR_INVALID_ARG_TYPE" /*message: /"keylen"/ */ },
},
+ {
+ args: ["", "", 42, null],
+ expected: { code: "ERR_INVALID_ARG_TYPE" },
+ },
// TODO: throw on these
// {
+ // args: ["", "", 42, {}],
+ // expected: { code: "ERR_INVALID_ARG_TYPE" },
+ // },
+ // {
+ // args: ["", "", 42, {}, {}],
+ // expected: { code: "ERR_INVALID_ARG_TYPE" },
+ // },
+ // {
+ // args: ["", "", 42, {}, null],
+ // expected: { code: "ERR_INVALID_ARG_TYPE" },
+ // },
+ // {
// args: ["", "", 0.42],
// expected: { code: "ERR_OUT_OF_RANGE" /*message: /"keylen"/ */ },
// },
@@ -170,41 +157,37 @@ const badargs = [
// args: ["", "", 2147485780],
// expected: { code: "ERR_OUT_OF_RANGE" /*message: /"keylen"/ */ },
// },
+ // {
+ // args: ["", "", 0, { maxmem: 2 ** 53 }],
+ // expected: { code: "ERR_OUT_OF_RANGE" /*message: /"keylen"/ */ },
+ // },
];
it("scrypt good", () => {
for (const options of good) {
const { pass, salt, keylen, expected } = options;
const actual = crypto.scryptSync(pass, salt, keylen, options);
- assert.strictEqual(actual.toString("hex"), expected);
+ expect(actual.toString("hex")).toBe(expected);
}
});
it("scrypt bad", () => {
for (const options of bad) {
- const expected = {
- message: /Invalid scrypt param/,
- };
- assert.throws(() => crypto.scryptSync("pass", "salt", 1, options), expected);
+ expect(() => crypto.scryptSync("pass", "salt", 1, options)).toThrow(/Invalid scrypt param/);
}
});
it("scrypt toobig", () => {
for (const options of toobig) {
- const expected = {
- message: /Invalid scrypt param/,
- };
- assert.throws(() => crypto.scryptSync("pass", "salt", 1, options), expected);
+ expect(() => crypto.scryptSync("pass", "salt", 1, options)).toThrow(/Invalid scrypt param/);
}
});
it("scrypt defaults eql", () => {
- {
- const defaults = { N: 16384, p: 1, r: 8 };
- const expected = crypto.scryptSync("pass", "salt", 1, defaults);
- const actual = crypto.scryptSync("pass", "salt", 1);
- assert.deepStrictEqual(actual.toString("hex"), expected.toString("hex"));
- }
+ const defaults = { N: 16384, p: 1, r: 8 };
+ const expected = crypto.scryptSync("pass", "salt", 1, defaults);
+ const actual = crypto.scryptSync("pass", "salt", 1);
+ expect(actual.toString("hex")).toBe(expected.toString("hex"));
});
// TODO: DEFAULT_ENCODING is read-only
@@ -217,27 +200,23 @@ it("scrypt defaults eql", () => {
// const testEncoding = "latin1";
// crypto.DEFAULT_ENCODING = testEncoding;
// const actual = crypto.scryptSync("pass", "salt", 1);
-// assert.deepStrictEqual(actual, expected.toString(testEncoding));
+// expect(actual).toBe(expected.toString(testEncoding));
// crypto.DEFAULT_ENCODING = defaultEncoding;
// }
// });
it("scrypt badargs", () => {
- {
- for (const { args, expected } of badargs) {
- assert.throws(() => crypto.scryptSync(...args), expected);
+ for (const { args, expected } of badargs) {
+ try {
+ crypto.scryptSync(...args);
+ expect(() => {}).toThrow();
+ } catch (e) {
+ if (!("code" in e)) throw e;
+ expect(e.code).toBe(expected.code);
}
}
- {
- const expected = { code: "ERR_INVALID_ARG_TYPE" };
- assert.throws(() => crypto.scryptSync("", "", 42, null), expected);
- // assert.throws(() => crypto.scryptSync("", "", 42, {}, null), expected);
- // assert.throws(() => crypto.scryptSync("", "", 42, {}), expected);
- // assert.throws(() => crypto.scryptSync("", "", 42, {}, {}), expected);
- }
-
// {
// // Values for maxmem that do not fit in 32 bits but that are still safe
// // integers should be allowed.
@@ -247,13 +226,7 @@ it("scrypt badargs", () => {
// 4,
// { maxmem: 2 ** 52 },
// common.mustSucceed((actual) => {
- // assert.strictEqual(actual.toString("hex"), "d72c87d0");
+ // expect(actual.toString("hex")).toBe("d72c87d0");
// }),
// );
-
- // // Values that exceed Number.isSafeInteger should not be allowed.
- // assert.throws(() => crypto.scryptSync("", "", 0, { maxmem: 2 ** 53 }), {
- // code: "ERR_OUT_OF_RANGE",
- // });
- // }
});
diff --git a/test/bun.js/test-test.test.ts b/test/bun.js/test-test.test.ts
index cc6d967c2..c83ee07a5 100644
--- a/test/bun.js/test-test.test.ts
+++ b/test/bun.js/test-test.test.ts
@@ -156,12 +156,21 @@ test("toThrow", () => {
throw err;
}).toThrow(err);
- var err = new Error("good");
expect(() => {
- throw err;
+ throw new Error("good");
}).toThrow();
expect(() => {
+ throw new Error("foo");
+ }).toThrow(/oo/);
+
+ expect(() =>
+ expect(() => {
+ throw new Error("bar");
+ }).toThrow(/baz/),
+ ).toThrow("/baz/");
+
+ expect(() => {
return true;
}).not.toThrow();