diff --git a/ReactNative/RealmReact.h b/ReactNative/RealmReact.h index 481b9fa2..0610c6b4 100644 --- a/ReactNative/RealmReact.h +++ b/ReactNative/RealmReact.h @@ -17,11 +17,10 @@ //////////////////////////////////////////////////////////////////////////// @import Foundation; +@import JavaScriptCore; + +extern JSGlobalContextRef RealmReactGetJSGlobalContextForExecutor(id executor); @interface RealmReact : NSObject -@property (nonatomic, readonly) id executor; - -+ (id)executor; - @end diff --git a/ReactNative/RealmReact.m b/ReactNative/RealmReact.m index 286fc017..98d23b57 100644 --- a/ReactNative/RealmReact.m +++ b/ReactNative/RealmReact.m @@ -21,7 +21,6 @@ @import GCDWebServers; @import RealmJS; -@import JavaScriptCore; @import ObjectiveC; @import Darwin; @@ -30,11 +29,16 @@ - (JSGlobalContextRef)ctx; @end +JSGlobalContextRef RealmReactGetJSGlobalContextForExecutor(id executor) { + Ivar contextIvar = class_getInstanceVariable([executor class], "_context"); + id rctJSContext = contextIvar ? object_getIvar(executor, contextIvar) : nil; + + return [rctJSContext ctx]; +} + @interface RealmReact () @end -static id s_executor; - @implementation RealmReact @synthesize bridge = _bridge; @@ -54,16 +58,12 @@ static id s_executor; return @"Realm"; } -+ (id)executor { - return s_executor; -} - - (void)setBridge:(RCTBridge *)bridge { _bridge = bridge; Ivar executorIvar = class_getInstanceVariable([bridge class], "_javaScriptExecutor"); - s_executor = object_getIvar(bridge, executorIvar); - Ivar contextIvar = class_getInstanceVariable([s_executor class], "_context"); + id executor = object_getIvar(bridge, executorIvar); + Ivar contextIvar = class_getInstanceVariable([executor class], "_context"); // The executor could be a RCTWebSocketExecutor, in which case it won't have a JS context. if (!contextIvar) { @@ -96,8 +96,8 @@ static id s_executor; return; } - [s_executor executeBlockOnJavaScriptQueue:^{ - id rctJSContext = object_getIvar(s_executor, contextIvar); + [executor executeBlockOnJavaScriptQueue:^{ + id rctJSContext = object_getIvar(executor, contextIvar); JSGlobalContextRef ctx; if (rctJSContext) { @@ -108,7 +108,7 @@ static id s_executor; if (RCTJavaScriptContext) { ctx = JSGlobalContextCreate(NULL); - object_setIvar(s_executor, contextIvar, [[RCTJavaScriptContext alloc] initWithJSContext:ctx]); + object_setIvar(executor, contextIvar, [[RCTJavaScriptContext alloc] initWithJSContext:ctx]); } else { NSLog(@"Failed to load RCTJavaScriptContext class"); diff --git a/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m b/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m index a4c7fcbc..abbf2081 100644 --- a/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m +++ b/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m @@ -22,13 +22,31 @@ @import RealmReact; +extern void JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx, bool includesNativeCallStack); + +static id s_currentJavaScriptExecutor; + @interface RealmReactTests : RealmJSTests @end @implementation RealmReactTests + (XCTestSuite *)defaultTestSuite { - [self waitForNotification:RCTJavaScriptDidLoadNotification]; + NSNotification *notification = [self waitForNotification:RCTJavaScriptDidLoadNotification]; + RCTBridge *bridge = notification.userInfo[@"bridge"]; + + if (!bridge) { + NSLog(@"No RCTBridge provided by RCTJavaScriptDidLoadNotification"); + exit(1); + } + + s_currentJavaScriptExecutor = [bridge valueForKey:@"javaScriptExecutor"]; + + // FIXME: Remove this nonsense once the crashes go away when a test fails! + JSGlobalContextRef ctx = RealmReactGetJSGlobalContextForExecutor(s_currentJavaScriptExecutor); + if (ctx) { + JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(ctx, false); + } NSError *error; NSDictionary *testCaseNames = [self invokeMethod:@"getTestNames" inModule:@"index" error:&error]; @@ -47,34 +65,34 @@ return suite; } -+ (void)waitForNotification:(NSString *)notificationName { ++ (NSNotification *)waitForNotification:(NSString *)notificationName { NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; - __block BOOL received = NO; + __block NSNotification *notification; id token = [nc addObserverForName:notificationName object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { - received = YES; + notification = note; }]; - while (!received) { + while (!notification) { @autoreleasepool { [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; } } [nc removeObserver:token]; + return notification; } + (id)invokeMethod:(NSString *)method inModule:(NSString *)module error:(NSError * __strong *)outError { module = [NSString stringWithFormat:@"realm-tests/%@.js", module]; - id executor = [RealmReact executor]; dispatch_group_t group = dispatch_group_create(); __block id result; dispatch_group_enter(group); - [executor executeJSCall:module method:method arguments:@[] callback:^(id json, NSError *error) { + [s_currentJavaScriptExecutor executeJSCall:module method:method arguments:@[] callback:^(id json, NSError *error) { result = json; if (error && outError) {