From d794213062faa73576fa0472a2b1319003167fef Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 22 Jul 2025 17:17:31 +0900 Subject: [PATCH] Add public `init(message:)` to `JSException` --- Sources/JavaScriptKit/JSException.swift | 8 +++ .../JavaScriptKitTests/JSExceptionTests.swift | 64 +++++++++++++++++++ .../JavaScriptKitTests.swift | 58 ----------------- Tests/prelude.mjs | 11 ---- 4 files changed, 72 insertions(+), 69 deletions(-) create mode 100644 Tests/JavaScriptKitTests/JSExceptionTests.swift diff --git a/Sources/JavaScriptKit/JSException.swift b/Sources/JavaScriptKit/JSException.swift index 1b9e311f..714b83aa 100644 --- a/Sources/JavaScriptKit/JSException.swift +++ b/Sources/JavaScriptKit/JSException.swift @@ -46,4 +46,12 @@ public struct JSException: Error, Equatable, CustomStringConvertible { self.stack = nil } } + + /// Initializes a new JavaScript `Error` instance with a message and prepare it to be thrown. + /// + /// - Parameters: + /// - message: The message to throw. + public init(message: String) { + self.init(JSError(message: message).jsValue) + } } diff --git a/Tests/JavaScriptKitTests/JSExceptionTests.swift b/Tests/JavaScriptKitTests/JSExceptionTests.swift new file mode 100644 index 00000000..4afd9ae3 --- /dev/null +++ b/Tests/JavaScriptKitTests/JSExceptionTests.swift @@ -0,0 +1,64 @@ +import XCTest +import JavaScriptKit + +class JSExceptionTests: XCTestCase { + private func eval(_ code: String) -> JSValue { + return JSObject.global.eval!(code) + } + + func testThrowingMethodCalls() { + let context = eval( + """ + (() => ({ + func1: () => { throw new Error(); }, + func2: () => { throw 'String Error'; }, + func3: () => { throw 3.0; }, + }))() + """ + ).object! + + // MARK: Throwing method calls + XCTAssertThrowsError(try context.throwing.func1!()) { error in + XCTAssertTrue(error is JSException) + let errorObject = JSError(from: (error as! JSException).thrownValue) + XCTAssertNotNil(errorObject) + } + + XCTAssertThrowsError(try context.throwing.func2!()) { error in + XCTAssertTrue(error is JSException) + let thrownValue = (error as! JSException).thrownValue + XCTAssertEqual(thrownValue.string, "String Error") + } + + XCTAssertThrowsError(try context.throwing.func3!()) { error in + XCTAssertTrue(error is JSException) + let thrownValue = (error as! JSException).thrownValue + XCTAssertEqual(thrownValue.number, 3.0) + } + } + + func testThrowingUnboundFunctionCalls() { + let jsThrowError = eval("() => { throw new Error(); }") + XCTAssertThrowsError(try jsThrowError.function!.throws()) { error in + XCTAssertTrue(error is JSException) + let errorObject = JSError(from: (error as! JSException).thrownValue) + XCTAssertNotNil(errorObject) + } + } + + func testThrowingConstructorCalls() { + let Animal = JSObject.global.Animal.function! + XCTAssertNoThrow(try Animal.throws.new("Tama", 3, true)) + XCTAssertThrowsError(try Animal.throws.new("Tama", -3, true)) { error in + XCTAssertTrue(error is JSException) + let errorObject = JSError(from: (error as! JSException).thrownValue) + XCTAssertNotNil(errorObject) + } + } + + func testInitWithMessage() { + let message = "THIS IS AN ERROR MESSAGE" + let exception = JSException(message: message) + XCTAssertTrue(exception.description.contains(message)) + } +} diff --git a/Tests/JavaScriptKitTests/JavaScriptKitTests.swift b/Tests/JavaScriptKitTests/JavaScriptKitTests.swift index 0e84283e..ffab816a 100644 --- a/Tests/JavaScriptKitTests/JavaScriptKitTests.swift +++ b/Tests/JavaScriptKitTests/JavaScriptKitTests.swift @@ -423,64 +423,6 @@ class JavaScriptKitTests: XCTestCase { globalObject1.prop_1.nested_prop = originalProp1 } - func testException() { - // ```js - // global.globalObject1 = { - // ... - // prop_9: { - // func1: function () { - // throw new Error(); - // }, - // func2: function () { - // throw "String Error"; - // }, - // func3: function () { - // throw 3.0 - // }, - // }, - // ... - // } - // ``` - // - let globalObject1 = JSObject.global.globalObject1 - let prop_9: JSValue = globalObject1.prop_9 - - // MARK: Throwing method calls - XCTAssertThrowsError(try prop_9.object!.throwing.func1!()) { error in - XCTAssertTrue(error is JSException) - let errorObject = JSError(from: (error as! JSException).thrownValue) - XCTAssertNotNil(errorObject) - } - - XCTAssertThrowsError(try prop_9.object!.throwing.func2!()) { error in - XCTAssertTrue(error is JSException) - let thrownValue = (error as! JSException).thrownValue - XCTAssertEqual(thrownValue.string, "String Error") - } - - XCTAssertThrowsError(try prop_9.object!.throwing.func3!()) { error in - XCTAssertTrue(error is JSException) - let thrownValue = (error as! JSException).thrownValue - XCTAssertEqual(thrownValue.number, 3.0) - } - - // MARK: Simple function calls - XCTAssertThrowsError(try prop_9.func1.function!.throws()) { error in - XCTAssertTrue(error is JSException) - let errorObject = JSError(from: (error as! JSException).thrownValue) - XCTAssertNotNil(errorObject) - } - - // MARK: Throwing constructor call - let Animal = JSObject.global.Animal.function! - XCTAssertNoThrow(try Animal.throws.new("Tama", 3, true)) - XCTAssertThrowsError(try Animal.throws.new("Tama", -3, true)) { error in - XCTAssertTrue(error is JSException) - let errorObject = JSError(from: (error as! JSException).thrownValue) - XCTAssertNotNil(errorObject) - } - } - func testSymbols() { let symbol1 = JSSymbol("abc") let symbol2 = JSSymbol("abc") diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 4a28d6aa..0d49045b 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -159,17 +159,6 @@ function setupTestGlobals(global) { }, prop_7: 3.14, prop_8: [0, , 2, 3, , , 6], - prop_9: { - func1: function () { - throw new Error(); - }, - func2: function () { - throw "String Error"; - }, - func3: function () { - throw 3.0; - }, - }, eval_closure: function (fn) { return fn(arguments[1]); },