Fix crash when a test fails inside RealmReactTests

This also appears to fix crashes when running ReactTests with Chrome debugging enabled!

The crash when tests failed was due to JavaScriptCore trying to create a backtrace with the native call stack.
This commit is contained in:
Scott Kyle 2015-10-15 16:18:58 -07:00
parent 7f5902b021
commit 5d59431860
3 changed files with 40 additions and 23 deletions

View File

@ -17,11 +17,10 @@
////////////////////////////////////////////////////////////////////////////
@import Foundation;
@import JavaScriptCore;
extern JSGlobalContextRef RealmReactGetJSGlobalContextForExecutor(id executor);
@interface RealmReact : NSObject
@property (nonatomic, readonly) id executor;
+ (id)executor;
@end

View File

@ -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 () <RCTBridgeModule>
@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");

View File

@ -22,13 +22,31 @@
@import RealmReact;
extern void JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx, bool includesNativeCallStack);
static id<RCTJavaScriptExecutor> 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<RCTJavaScriptExecutor> 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) {