guardia-messenger/node_modules/expo-modules-core/ios/Tests/FunctionSpec.swift
DESKTOP-TKLFCPRython f29f525c77 refactor: 101.79.17.164 → zioinfo.co.kr 전체 도메인 변환 + Manager UI 배포
- 37개 파일 IP → zioinfo.co.kr 치환 (소스/매뉴얼/설정/하네스)
- Manager DrConsole/NetworkConsole/CsapConsole 빌드 + /var/www/manager/ 배포
- 테스트: Manager HTTP 200, ITSM 신규 API 7개 전체 200

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 10:09:17 +09:00

315 lines
10 KiB
Swift

import ExpoModulesTestCore
@testable import ExpoModulesCore
class FunctionSpec: ExpoSpec {
override class func spec() {
let appContext = AppContext.create()
let functionName = "test function name"
context("native") {
func testFunctionReturning<T: Equatable>(value returnValue: T) {
waitUntil { done in
mockModuleHolder(appContext) {
AsyncFunction(functionName) {
return returnValue
}
}
.call(function: functionName, args: []) { result in
let value = try! result.get()
expect(value).notTo(beNil())
expect(value).to(beAKindOf(T.self))
expect(value as? T).to(equal(returnValue))
done()
}
}
}
it("is called") {
waitUntil { done in
mockModuleHolder(appContext) {
AsyncFunction(functionName) {
done()
}
}
.call(function: functionName, args: [])
}
}
it("returns bool values") {
testFunctionReturning(value: true)
testFunctionReturning(value: false)
testFunctionReturning(value: [true, false])
}
it("returns int values") {
testFunctionReturning(value: 1_234)
testFunctionReturning(value: [2, 1, 3, 7])
}
it("returns double values") {
testFunctionReturning(value: 3.14)
testFunctionReturning(value: [0, 1.1, 2.2])
}
it("returns string values") {
testFunctionReturning(value: "a string")
testFunctionReturning(value: ["expo", "modules", "core"])
}
it("is called with nil value") {
let str: String? = nil
mockModuleHolder(appContext) {
AsyncFunction(functionName) { (a: String?) in
expect(a == nil) == true
}
}
.callSync(function: functionName, args: [str as Any])
}
it("is called with an array of arrays") {
let array: [[String]] = [["expo"]]
mockModuleHolder(appContext) {
AsyncFunction(functionName) { (a: [[String]]) in
expect(a.first!.first) == array.first!.first
}
}
.callSync(function: functionName, args: [array])
}
describe("converting records") {
struct TestRecord: Record {
@Field var property: String = "expo"
@Field var optionalProperty: Int?
@Field("propertyWithCustomKey") var customKeyProperty: String = "expo"
}
let dict = [
"property": "Hello",
"propertyWithCustomKey": "Expo!"
]
it("converts to simple record when passed as an argument") {
waitUntil { done in
mockModuleHolder(appContext) {
AsyncFunction(functionName) { (a: TestRecord) in
return a.property
}
}
.call(function: functionName, args: [dict]) { result in
let value = try! result.get()
expect(value).notTo(beNil())
expect(value).to(beAKindOf(String.self))
expect(value as? String).to(equal(dict["property"]!))
done()
}
}
}
it("converts to record with custom key") {
waitUntil { done in
mockModuleHolder(appContext) {
AsyncFunction(functionName) { (a: TestRecord) in
return a.customKeyProperty
}
}
.call(function: functionName, args: [dict]) { result in
let value = try! result.get()
expect(value).notTo(beNil())
expect(value).to(beAKindOf(String.self))
expect(value as? String).to(equal(dict["propertyWithCustomKey"]))
done()
}
}
}
it("returns the record back (sync)") {
let result = try Function(functionName) { (record: TestRecord) in record }
.call(by: nil, withArguments: [dict], appContext: appContext) as? TestRecord
guard let result = Conversions.convertFunctionResult(result, appContext: appContext) as? TestRecord.Dict else {
return fail()
}
expect(result).notTo(beNil())
expect(result["property"] as? String).to(equal(dict["property"]))
expect(result["propertyWithCustomKey"] as? String).to(equal(dict["propertyWithCustomKey"]))
}
it("returns the record back (async)") {
waitUntil { done in
mockModuleHolder(appContext) {
AsyncFunction(functionName) { (a: TestRecord) in
return a
}
}
.call(function: functionName, args: [dict]) { result in
let value = try! result.get()
expect(value).notTo(beNil())
expect(value).to(beAKindOf(Record.Dict.self))
let valueAsDict = value as! Record.Dict
expect(valueAsDict["property"] as? String).to(equal(dict["property"]))
expect(valueAsDict["propertyWithCustomKey"] as? String).to(equal(dict["propertyWithCustomKey"]))
done()
}
}
}
}
it("throws when called with more arguments than expected") {
waitUntil { done in
mockModuleHolder(appContext) {
AsyncFunction(functionName) { (_: Int) in
return "something"
}
}
// Function expects one argument, let's give it more.
.call(function: functionName, args: [1, 2]) { result in
switch result {
case .failure(let error):
expect(error).notTo(beNil())
expect(error).to(beAKindOf(InvalidArgsNumberException.self))
case .success(_):
fail()
}
done()
}
}
}
it("allows to skip trailing optional arguments") {
let returnedValue = "something"
let fn = Function(functionName) { (a: String, b: Int?, c: Bool?) in
expect(c).to(beNil())
return returnedValue
}
expect({ (try fn.call(by: nil, withArguments: ["test"], appContext: appContext)) as? String })
.notTo(throwError())
.to(equal(returnedValue))
expect({ (try fn.call(by: nil, withArguments: ["test", 3], appContext: appContext)) as? String })
.notTo(throwError())
.to(equal(returnedValue))
}
it("throws when called without required arguments") {
let fn = Function(functionName) { (requiredArgument: String, optionalArgument: Int?) in
return "something"
}
expect({ try fn.call(by: nil, withArguments: [], appContext: appContext) })
.to(throwError(errorType: FunctionCallException.self) { error in
expect(error.rootCause).to(beAKindOf(InvalidArgsNumberException.self))
let exception = error.rootCause as! InvalidArgsNumberException
expect(exception.param.received) == 0
expect(exception.param.required) == 1
expect(exception.param.expected) == 2
})
}
it("throws when called with arguments of incompatible types") {
waitUntil { done in
mockModuleHolder(appContext) {
AsyncFunction(functionName) { (_: String) in
return "something"
}
}
// Function expects a string, let's give it a number.
.call(function: functionName, args: [1]) { result in
switch result {
case .failure(let error):
expect(error).notTo(beNil())
expect(error).to(beAKindOf(FunctionCallException.self))
expect(error.isCausedBy(ArgumentCastException.self)) == true
expect(error.isCausedBy(Conversions.CastingException<String>.self)) == true
case .success(_):
fail()
}
done()
}
}
}
}
context("JavaScript") {
let runtime = try! appContext.runtime
beforeSuite {
appContext.moduleRegistry.register(holder: mockModuleHolder(appContext) {
Name("TestModule")
Function("returnPi") { Double.pi }
Function("returnNull") { () -> Double? in
return nil
}
Function("isArgNull") { (arg: Double?) -> Bool in
return arg == nil
}
Function("returnObjectDefinition") { (initial: Int) -> ObjectDefinition in
var foo = initial
return Object {
Function("increment") { () -> Int in
foo += 1
return foo
}
}
}
Function("withFunction") { (fn: JavaScriptFunction<String>) -> String in
return try fn.call("foo", "bar")
}
Function("withCGFloat") { (f: CGFloat) in
return "\(f)"
}
})
}
it("returns values") {
expect(try runtime.eval("expo.modules.TestModule.returnPi()").asDouble()) == Double.pi
expect(try runtime.eval("expo.modules.TestModule.returnNull()").isNull()) == true
}
it("accepts optional arguments") {
expect(try runtime.eval("expo.modules.TestModule.isArgNull(3.14)").asBool()) == false
expect(try runtime.eval("expo.modules.TestModule.isArgNull(null)").asBool()) == true
}
it("returns object made from definition") {
let initialValue = Int.random(in: 1..<100)
let object = try runtime.eval("object = expo.modules.TestModule.returnObjectDefinition(\(initialValue))")
expect(object.kind) == .object
expect(object.getObject().hasProperty("increment")) == true
let result = try runtime.eval("object.increment()")
expect(result.kind) == .number
expect(result.getInt()) == initialValue + 1
}
it("takes JavaScriptFunction argument") {
let value = try runtime.eval("expo.modules.TestModule.withFunction((a, b) => a + b)")
expect(value.kind) == .string
expect(value.getString()) == "foobar"
}
it("accepts CGFloat argument") {
expect(try runtime.eval("expo.modules.TestModule.withCGFloat(20.23)").asString()) == "20.23"
}
}
}
}