import ExpoModulesTestCore @testable import ExpoModulesCore final class SharedObjectSpec: ExpoSpec { override class func spec() { let appContext = AppContext.create() let runtime = try! appContext.runtime beforeSuite { appContext.moduleRegistry.register(moduleType: SharedObjectModule.self) } describe("Base JS class") { it("exists") { let baseSharedObjectClass = try runtime.eval("expo.SharedObject") expect(baseSharedObjectClass.kind) == .function } it("has release function in prototype") { let releaseFunction = try runtime.eval("expo.SharedObject.prototype.release") expect(releaseFunction.kind) == .function } it("initializes") { let sharedObject = try runtime.eval("new expo.SharedObject()") expect(sharedObject.kind) == .object } it("does not register") { let registrySizeBefore = appContext.sharedObjectRegistry.size try runtime.eval("new expo.SharedObject()") expect(appContext.sharedObjectRegistry.size) == registrySizeBefore } it("inherits from EventEmitter") { let isEventEmitter = try runtime.eval("new expo.SharedObject() instanceof expo.EventEmitter") expect(isEventEmitter.kind) == .bool expect(try isEventEmitter.asBool()) == true } } describe("Concrete JS class") { it("exists") { let sharedObjectClass = try runtime.eval("expo.modules.SharedObjectModule.SharedObjectExample") expect(sharedObjectClass.kind) == .function } it("has base class prototype") { let hasBaseClassPrototype = try runtime.eval("expo.modules.SharedObjectModule.SharedObjectExample.prototype instanceof expo.SharedObject") expect(hasBaseClassPrototype.kind) == .bool expect(try hasBaseClassPrototype.asBool()) == true } it("creates new instance") { let sharedObject = try runtime.eval("new expo.modules.SharedObjectModule.SharedObjectExample()") expect(sharedObject.kind) == .object } it("registers") { let registrySizeBefore = appContext.sharedObjectRegistry.size try runtime.eval("new expo.modules.SharedObjectModule.SharedObjectExample()") expect(appContext.sharedObjectRegistry.size) == registrySizeBefore + 1 } it("is instance of") { let isInstanceOf = try runtime.eval([ "sharedObject = new expo.modules.SharedObjectModule.SharedObjectExample()", "sharedObject instanceof expo.modules.SharedObjectModule.SharedObjectExample" ]) expect(isInstanceOf.kind) == .bool expect(try isInstanceOf.asBool()) == true } it("is instance of base class") { let isInstanceOfBaseClass = try runtime.eval([ "sharedObject = new expo.modules.SharedObjectModule.SharedObjectExample()", "sharedObject instanceof expo.SharedObject" ]) expect(isInstanceOfBaseClass.kind) == .bool expect(try isInstanceOfBaseClass.asBool()) == true } it("has function from base class") { let releaseFunction = try runtime.eval([ "sharedObject = new expo.modules.SharedObjectModule.SharedObjectExample()", "sharedObject.release" ]) expect(releaseFunction.kind) == .function } } describe("Native object") { // Event emitting requires Xcode 15.0, but we're still using Xcode 14 // to run these tests on GitHub Actions due to some performance issues. #if swift(>=5.9) it("emits events") { // Create the shared object let jsObject = try runtime .eval("sharedObject = new expo.modules.SharedObjectModule.SharedObjectExample()") .asObject() // Add a listener that adds three arguments try runtime.eval([ "result = null", "sharedObject.addListener('test event', (number, string, record) => { result = { number, string, record } })" ]) // Get the native instance let nativeObject = appContext.sharedObjectRegistry.toNativeObject(jsObject) struct EventRecord: Record { @Field var boolean: Bool = true } // Emit an event from the native object to JS nativeObject?.emit(event: "test event", arguments: 123, "test", EventRecord()) // Check the value that is set by the listener let result = try runtime.eval("result").asObject() expect(try result.getProperty("number").asInt()) == 123 expect(try result.getProperty("string").asString()) == "test" expect(try result.getProperty("record").asObject().getProperty("boolean").asBool()) == true } #endif // swift(>=5.9) } } } private class SharedObjectModule: Module { public func definition() -> ModuleDefinition { Class(SharedObjectExample.self) { Constructor { return SharedObjectExample() } } } } private final class SharedObjectExample: SharedObject {}