diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/RCTUIManagerScenarioTests.m b/Examples/UIExplorer/UIExplorerIntegrationTests/RCTUIManagerScenarioTests.m index c30b8d1dc..137612b9e 100644 --- a/Examples/UIExplorer/UIExplorerIntegrationTests/RCTUIManagerScenarioTests.m +++ b/Examples/UIExplorer/UIExplorerIntegrationTests/RCTUIManagerScenarioTests.m @@ -12,7 +12,6 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - #import #import #import "RCTSparseArray.h" diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerIntegrationTests.m b/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerIntegrationTests.m index fc9afeaf1..834f60901 100644 --- a/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerIntegrationTests.m +++ b/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerIntegrationTests.m @@ -47,7 +47,7 @@ [_runner runTest:_cmd module:@"IntegrationTestHarnessTest" initialProps:@{@"waitOneFrame": @YES} - expectErrorBlock:nil]; +configurationBlock:nil]; } - (void)testTheTester_ExpectError @@ -55,6 +55,7 @@ [_runner runTest:_cmd module:@"IntegrationTestHarnessTest" initialProps:@{@"shouldThrow": @YES} +configurationBlock:nil expectErrorRegex:@"because shouldThrow"]; } diff --git a/Libraries/RCTTest/RCTTestRunner.h b/Libraries/RCTTest/RCTTestRunner.h index 097bef6bf..ce4a85f2f 100644 --- a/Libraries/RCTTest/RCTTestRunner.h +++ b/Libraries/RCTTest/RCTTestRunner.h @@ -24,6 +24,8 @@ @protocol RCTBridgeModule; +@class RCTRootView; + @interface RCTTestRunner : NSObject @property (nonatomic, assign) BOOL recordMode; @@ -59,26 +61,42 @@ /** * Same as runTest:, but allows for passing initialProps for providing mock data - * or requesting different behaviors, and expectErrorRegex verifies that the - * error you expected was thrown. + * or requesting different behaviors, configurationBlock provides arbitrary logic for the hosting + * root view manipulation. * * @param test Selector of the test, usually just `_cmd`. * @param moduleName Name of the JS component as registered by `AppRegistry.registerComponent` in JS. * @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. + * @param configurationBlock A block that takes the hosting root view and performs arbitrary manipulation after its creation. */ -- (void)runTest:(SEL)test module:(NSString *)moduleName initialProps:(NSDictionary *)initialProps expectErrorRegex:(NSString *)expectErrorRegex; + +- (void)runTest:(SEL)test module:(NSString *)moduleName initialProps:(NSDictionary *)initialProps configurationBlock:(void(^)(RCTRootView *rootView))configurationBlock; /** * Same as runTest:, but allows for passing initialProps for providing mock data - * or requesting different behaviors, and expectErrorBlock provides arbitrary + * or requesting different behaviors, configurationBlock provides arbitrary logic for the hosting + * root view manipulation, and expectErrorRegex verifies that the error you expected was thrown. + * + * @param test Selector of the test, usually just `_cmd`. + * @param moduleName Name of the JS component as registered by `AppRegistry.registerComponent` in JS. + * @param initialProps props that are passed into the component when rendered. + * @param configurationBlock A block that takes the hosting root view and performs arbitrary manipulation after its creation. + * @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 configurationBlock:(void(^)(RCTRootView *rootView))configurationBlock expectErrorRegex:(NSString *)expectErrorRegex; + +/** + * Same as runTest:, but allows for passing initialProps for providing mock data + * or requesting different behaviors, configurationBlock provides arbitrary logic for the hosting + * root view manipulation, and expectErrorBlock provides arbitrary * logic for processing errors (nil will cause any error to fail the test). * * @param test Selector of the test, usually just `_cmd`. * @param moduleName Name of the JS component as registered by `AppRegistry.registerComponent` in JS. * @param initialProps props that are passed into the component when rendered. + * @param configurationBlock A block that takes the hosting root view and performs arbitrary manipulation after its creation. * @param expectErrorBlock A block that takes the error message and returns NO to fail the test. */ -- (void)runTest:(SEL)test module:(NSString *)moduleName initialProps:(NSDictionary *)initialProps expectErrorBlock:(BOOL(^)(NSString *error))expectErrorBlock; +- (void)runTest:(SEL)test module:(NSString *)moduleName initialProps:(NSDictionary *)initialProps configurationBlock:(void(^)(RCTRootView *rootView))configurationBlock expectErrorBlock:(BOOL(^)(NSString *error))expectErrorBlock; @end diff --git a/Libraries/RCTTest/RCTTestRunner.m b/Libraries/RCTTest/RCTTestRunner.m index 1e5cd448e..16e911811 100644 --- a/Libraries/RCTTest/RCTTestRunner.m +++ b/Libraries/RCTTest/RCTTestRunner.m @@ -68,19 +68,24 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) - (void)runTest:(SEL)test module:(NSString *)moduleName { - [self runTest:test module:moduleName initialProps:nil expectErrorBlock:nil]; + [self runTest:test module:moduleName initialProps:nil configurationBlock:nil expectErrorBlock:nil]; } -- (void)runTest:(SEL)test module:(NSString *)moduleName - initialProps:(NSDictionary *)initialProps expectErrorRegex:(NSString *)errorRegex +- (void)runTest:(SEL)test module:(NSString *)moduleName initialProps:(NSDictionary *)initialProps configurationBlock:(void(^)(RCTRootView *rootView))configurationBlock { - [self runTest:test module:moduleName initialProps:initialProps expectErrorBlock:^BOOL(NSString *error){ - return [error rangeOfString:errorRegex options:NSRegularExpressionSearch].location != NSNotFound; - }]; + [self runTest:test module:moduleName initialProps:initialProps configurationBlock:configurationBlock expectErrorBlock:nil]; } -- (void)runTest:(SEL)test module:(NSString *)moduleName - initialProps:(NSDictionary *)initialProps expectErrorBlock:(BOOL(^)(NSString *error))expectErrorBlock +- (void)runTest:(SEL)test module:(NSString *)moduleName initialProps:(NSDictionary *)initialProps configurationBlock:(void(^)(RCTRootView *rootView))configurationBlock expectErrorRegex:(NSString *)errorRegex +{ + BOOL(^expectErrorBlock)(NSString *error) = ^BOOL(NSString *error){ + return [error rangeOfString:errorRegex options:NSRegularExpressionSearch].location != NSNotFound; + }; + + [self runTest:test module:moduleName initialProps:initialProps configurationBlock:configurationBlock expectErrorBlock:expectErrorBlock]; +} + +- (void)runTest:(SEL)test module:(NSString *)moduleName initialProps:(NSDictionary *)initialProps configurationBlock:(void(^)(RCTRootView *rootView))configurationBlock expectErrorBlock:(BOOL(^)(NSString *error))expectErrorBlock { __weak id weakJSContext; @@ -110,6 +115,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) vc.view = [UIView new]; [vc.view addSubview:rootView]; // Add as subview so it doesn't get resized + if (configurationBlock) { + configurationBlock(rootView); + } + NSDate *date = [NSDate dateWithTimeIntervalSinceNow:kTestTimeoutSeconds]; while (date.timeIntervalSinceNow > 0 && testModule.status == RCTTestStatusPending && error == nil) { [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];