This commit is contained in:
Nick Lockwood
2015-04-11 15:08:00 -07:00
parent 699a9c3e0c
commit 26fd24dc50
21 changed files with 504 additions and 485 deletions

View File

@@ -21,7 +21,7 @@
@interface RCTTestRunner : NSObject
@property (nonatomic, assign) BOOL recordMode;
@property (nonatomic, copy) NSString *script;
@property (nonatomic, strong) NSURL *scriptURL;
/**
* Initialize a runner. It's recommended that you use the initRunnerForApp macro instead of calling this directly.
@@ -55,7 +55,7 @@
* @param initialProps props that are passed into the component when rendered.
* @param expectErrorRegex A regex that must match the error thrown. If no error is thrown, the test fails.
*/
- (void)runTest:(SEL)test module:(NSString *)moduleName initialProps:(NSDictionary *)initialProps expectErrorRegex:(NSRegularExpression *)expectErrorRegex;
- (void)runTest:(SEL)test module:(NSString *)moduleName initialProps:(NSDictionary *)initialProps expectErrorRegex:(NSString *)expectErrorRegex;
/**
* Same as runTest:, but allows for passing initialProps for providing mock data or requesting different behaviors, and

View File

@@ -29,7 +29,7 @@
sanitizedAppName = [sanitizedAppName stringByReplacingOccurrencesOfString:@"\\" withString:@"-"];
_snapshotController = [[FBSnapshotTestController alloc] initWithTestName:sanitizedAppName];
_snapshotController.referenceImagesDirectory = referenceDir;
_script = [NSString stringWithFormat:@"http://localhost:8081/%@.includeRequire.runModule.bundle?dev=true", app];
_scriptURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:8081/%@.includeRequire.runModule.bundle?dev=true", app]];
}
return self;
}
@@ -49,10 +49,10 @@
[self runTest:test module:moduleName initialProps:nil expectErrorBlock:nil];
}
- (void)runTest:(SEL)test module:(NSString *)moduleName initialProps:(NSDictionary *)initialProps expectErrorRegex:(NSRegularExpression *)errorRegex
- (void)runTest:(SEL)test module:(NSString *)moduleName initialProps:(NSDictionary *)initialProps expectErrorRegex:(NSString *)errorRegex
{
[self runTest:test module:moduleName initialProps:initialProps expectErrorBlock:^BOOL(NSString *error){
return [errorRegex numberOfMatchesInString:error options:0 range:NSMakeRange(0, [error length])] > 0;
return [error rangeOfString:errorRegex options:NSRegularExpressionSearch].location != NSNotFound;
}];
}
@@ -66,11 +66,12 @@
RCTTestModule *testModule = [[RCTTestModule alloc] initWithSnapshotController:_snapshotController view:nil];
testModule.testSelector = test;
RCTBridge *bridge = [[RCTBridge alloc] initWithBundlePath:_script
moduleProvider:^(){
return @[testModule];
}
launchOptions:nil];
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_scriptURL
moduleProvider:^(){
return @[testModule];
}
launchOptions:nil];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:moduleName];
testModule.view = rootView;

View File

@@ -11,6 +11,6 @@
@interface RCTWebSocketExecutor : NSObject <RCTJavaScriptExecutor>
- (instancetype)initWithURL:(NSURL *)url;
- (instancetype)initWithURL:(NSURL *)URL;
@end

View File

@@ -10,6 +10,7 @@
#import "RCTWebSocketExecutor.h"
#import "RCTLog.h"
#import "RCTSparseArray.h"
#import "RCTUtils.h"
#import "SRWebSocket.h"
@@ -18,10 +19,11 @@ typedef void (^WSMessageCallback)(NSError *error, NSDictionary *reply);
@interface RCTWebSocketExecutor () <SRWebSocketDelegate>
@end
@implementation RCTWebSocketExecutor {
@implementation RCTWebSocketExecutor
{
SRWebSocket *_socket;
NSOperationQueue *_jsQueue;
NSMutableDictionary *_callbacks;
dispatch_queue_t _jsQueue;
RCTSparseArray *_callbacks;
dispatch_semaphore_t _socketOpenSemaphore;
NSMutableDictionary *_injectedObjects;
}
@@ -31,23 +33,24 @@ typedef void (^WSMessageCallback)(NSError *error, NSDictionary *reply);
return [self initWithURL:[NSURL URLWithString:@"http://localhost:8081/debugger-proxy"]];
}
- (instancetype)initWithURL:(NSURL *)url
- (instancetype)initWithURL:(NSURL *)URL
{
if (self = [super init]) {
_jsQueue = [[NSOperationQueue alloc] init];
_jsQueue.maxConcurrentOperationCount = 1;
_socket = [[SRWebSocket alloc] initWithURL:url];
_jsQueue = dispatch_queue_create("com.facebook.React.WebSocketExecutor", DISPATCH_QUEUE_SERIAL);
_socket = [[SRWebSocket alloc] initWithURL:URL];
_socket.delegate = self;
_callbacks = [NSMutableDictionary dictionary];
_injectedObjects = [NSMutableDictionary dictionary];
[_socket setDelegateOperationQueue:_jsQueue];
_callbacks = [[RCTSparseArray alloc] init];
_injectedObjects = [[NSMutableDictionary alloc] init];
[_socket setDelegateDispatchQueue:_jsQueue];
NSURL *startDevToolsURL = [NSURL URLWithString:@"/launch-chrome-devtools" relativeToURL:url];
NSURL *startDevToolsURL = [NSURL URLWithString:@"/launch-chrome-devtools" relativeToURL:URL];
[NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:startDevToolsURL] delegate:nil];
if (![self connectToProxy]) {
RCTLogError(@"Connection to %@ timed out. Are you running node proxy? If you are running on the device check if you have the right IP address on `RCTWebSocketExecutor.m` file.", url);
RCTLogError(@"Connection to %@ timed out. Are you running node proxy? If \
you are running on the device, check if you have the right IP \
address in `RCTWebSocketExecutor.m`.", URL);
[self invalidate];
return nil;
}
@@ -91,8 +94,8 @@ typedef void (^WSMessageCallback)(NSError *error, NSDictionary *reply);
{
NSError *error = nil;
NSDictionary *reply = RCTJSONParse(message, &error);
NSUInteger messageID = [reply[@"replyID"] integerValue];
WSMessageCallback callback = [_callbacks objectForKey:@(messageID)];
NSNumber *messageID = reply[@"replyID"];
WSMessageCallback callback = _callbacks[messageID];
if (callback) {
callback(error, reply);
}
@@ -108,16 +111,11 @@ typedef void (^WSMessageCallback)(NSError *error, NSDictionary *reply);
RCTLogError(@"WebSocket connection failed with error %@", error);
}
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean
{
}
- (void)sendMessage:(NSDictionary *)message waitForReply:(WSMessageCallback)callback
{
static NSUInteger lastID = 10000;
[_jsQueue addOperationWithBlock:^{
dispatch_async(_jsQueue, ^{
if (!self.valid) {
NSError *error = [NSError errorWithDomain:@"WS" code:1 userInfo:@{
NSLocalizedDescriptionKey: @"socket closed"
@@ -126,19 +124,17 @@ typedef void (^WSMessageCallback)(NSError *error, NSDictionary *reply);
return;
}
NSUInteger expectedID = lastID++;
_callbacks[@(expectedID)] = [callback copy];
NSNumber *expectedID = @(lastID++);
_callbacks[expectedID] = [callback copy];
NSMutableDictionary *messageWithID = [message mutableCopy];
messageWithID[@"id"] = @(expectedID);
messageWithID[@"id"] = expectedID;
[_socket send:RCTJSONStringify(messageWithID, NULL)];
}];
});
}
- (void)executeApplicationScript:(NSString *)script sourceURL:(NSURL *)url onComplete:(RCTJavaScriptCompleteBlock)onComplete
- (void)executeApplicationScript:(NSString *)script sourceURL:(NSURL *)URL onComplete:(RCTJavaScriptCompleteBlock)onComplete
{
NSDictionary *message = @{@"method": NSStringFromSelector(_cmd), @"url": [url absoluteString], @"inject": _injectedObjects};
NSDictionary *message = @{@"method": NSStringFromSelector(_cmd), @"url": [URL absoluteString], @"inject": _injectedObjects};
[self sendMessage:message waitForReply:^(NSError *error, NSDictionary *reply) {
onComplete(error);
}];
@@ -147,7 +143,12 @@ typedef void (^WSMessageCallback)(NSError *error, NSDictionary *reply);
- (void)executeJSCall:(NSString *)name method:(NSString *)method arguments:(NSArray *)arguments callback:(RCTJavaScriptCallback)onComplete
{
RCTAssert(onComplete != nil, @"callback was missing for exec JS call");
NSDictionary *message = @{@"method": NSStringFromSelector(_cmd), @"moduleName": name, @"moduleMethod": method, @"arguments": arguments};
NSDictionary *message = @{
@"method": NSStringFromSelector(_cmd),
@"moduleName": name,
@"moduleMethod": method,
@"arguments": arguments
};
[self sendMessage:message waitForReply:^(NSError *socketError, NSDictionary *reply) {
if (socketError) {
onComplete(nil, socketError);
@@ -162,15 +163,14 @@ typedef void (^WSMessageCallback)(NSError *error, NSDictionary *reply);
- (void)injectJSONText:(NSString *)script asGlobalObjectNamed:(NSString *)objectName callback:(RCTJavaScriptCompleteBlock)onComplete
{
[_jsQueue addOperationWithBlock:^{
[_injectedObjects setObject:script forKey:objectName];
dispatch_async(_jsQueue, ^{
_injectedObjects[objectName] = script;
onComplete(nil);
}];
});
}
- (void)invalidate
{
[_jsQueue cancelAllOperations];
_socket.delegate = nil;
[_socket closeWithCode:1000 reason:@"Invalidated"];
_socket = nil;