diff options
author | 2023-03-06 03:33:38 +0200 | |
---|---|---|
committer | 2023-03-06 03:33:38 +0200 | |
commit | d4bd156d9d3bebbf447e84183d4b49dea0b531cd (patch) | |
tree | 81a20e93fc3788c2a47e02786359ae4e32aed644 | |
parent | c7bfb3aa3acdd1c8b11782530110aaf417cb79b8 (diff) | |
download | bun-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.ts | 2 | ||||
-rw-r--r-- | src/bun.js/test/jest.zig | 77 | ||||
-rw-r--r-- | test/bun.js/console/console-log.expected.txt | 2 | ||||
-rw-r--r-- | test/bun.js/console/console-log.js | 2 | ||||
-rw-r--r-- | test/bun.js/crypto-scrypt.test.js | 99 | ||||
-rw-r--r-- | test/bun.js/test-test.test.ts | 13 |
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(); |