#import #import #import #import #import "RNNTestRootViewCreator.h" #import #import #import #import #import "RNNLayoutManager.h" #import "RNNBottomTabsController.h" #import "BottomTabsAttachModeFactory.h" #import #import "RNNComponentViewController+Utils.h" @interface MockUINavigationController : RNNStackController @property (nonatomic, strong) NSArray* willReturnVCs; @end @implementation MockUINavigationController -(NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated { return self.willReturnVCs; } -(NSArray *)popToRootViewControllerAnimated:(BOOL)animated { return self.willReturnVCs; } @end @interface RNNCommandsHandlerTest : XCTestCase @property (nonatomic, strong) RNNCommandsHandler* uut; @property (nonatomic, strong) id modalManager; @property (nonatomic, strong) RNNComponentViewController* vc1; @property (nonatomic, strong) RNNComponentViewController* vc2; @property (nonatomic, strong) RNNComponentViewController* vc3; @property (nonatomic, strong) MockUINavigationController* nvc; @property (nonatomic, strong) id mainWindow; @property (nonatomic, strong) id sharedApplication; @property (nonatomic, strong) id controllerFactory; @property (nonatomic, strong) id overlayManager; @property (nonatomic, strong) id eventEmmiter; @property (nonatomic, strong) id creator; @end @implementation RNNCommandsHandlerTest - (void)setUp { [super setUp]; self.creator = [OCMockObject partialMockForObject:[RNNTestRootViewCreator new]]; self.mainWindow = [OCMockObject partialMockForObject:[UIWindow new]]; self.eventEmmiter = [OCMockObject partialMockForObject:[RNNEventEmitter new]]; self.overlayManager = [OCMockObject partialMockForObject:[RNNOverlayManager new]]; self.modalManager = [OCMockObject partialMockForObject:[RNNModalManager new]]; self.controllerFactory = [OCMockObject partialMockForObject:[[RNNControllerFactory alloc] initWithRootViewCreator:nil eventEmitter:self.eventEmmiter store:nil componentRegistry:nil andBridge:nil bottomTabsAttachModeFactory:[BottomTabsAttachModeFactory new]]]; self.uut = [[RNNCommandsHandler alloc] initWithControllerFactory:self.controllerFactory eventEmitter:self.eventEmmiter modalManager:self.modalManager overlayManager:self.overlayManager mainWindow:_mainWindow]; self.vc1 = [self generateComponentWithComponentId:@"1"]; self.vc2 = [self generateComponentWithComponentId:@"2"]; self.vc3 = [self generateComponentWithComponentId:@"3"]; _nvc = [[MockUINavigationController alloc] init]; [_nvc setViewControllers:@[self.vc1, self.vc2, self.vc3]]; UIApplication* sharedApplication = [OCMockObject niceMockForClass:[UIApplication class]]; id mockedApplicationClass = OCMClassMock([UIApplication class]); OCMStub(ClassMethod([mockedApplicationClass sharedApplication])).andReturn(sharedApplication); OCMStub(sharedApplication.keyWindow).andReturn(self.mainWindow); OCMStub([sharedApplication windows]).andReturn(@[self.mainWindow]); } - (RNNComponentViewController *)generateComponentWithComponentId:(NSString *)componentId { RNNLayoutInfo* layoutInfo = [[RNNLayoutInfo alloc] init]; layoutInfo.componentId = componentId; return [[RNNComponentViewController alloc] initWithLayoutInfo:layoutInfo rootViewCreator:_creator eventEmitter:nil presenter:[RNNComponentPresenter new] options:[[RNNNavigationOptions alloc] initWithDict:@{}] defaultOptions:nil]; } - (void)testAssertReadyForEachMethodThrowsExceptions { NSArray* methods = [self getPublicMethodNamesForObject:self.uut]; [self.uut setReadyToReceiveCommands:false]; for (NSString* methodName in methods) { SEL s = NSSelectorFromString(methodName); IMP imp = [self.uut methodForSelector:s]; void (*func)(id, SEL, id, id, id, id, id) = (void *)imp; XCTAssertThrowsSpecificNamed(func(self.uut,s, nil, nil, nil, nil, nil), NSException, @"BridgeNotLoadedError"); } } - (NSArray*)getPublicMethodNamesForObject:(NSObject*)obj { NSMutableArray* skipMethods = [NSMutableArray new]; [skipMethods addObject:@"initWithControllerFactory:eventEmitter:modalManager:overlayManager:mainWindow:"]; [skipMethods addObject:@"assertReady"]; [skipMethods addObject:@"setReadyToReceiveCommands:"]; [skipMethods addObject:@"readyToReceiveCommands"]; [skipMethods addObject:@".cxx_destruct"]; [skipMethods addObject:@"dismissedModal:"]; [skipMethods addObject:@"attemptedToDismissModal:"]; [skipMethods addObject:@"dismissedMultipleModals:"]; NSMutableArray* result = [NSMutableArray new]; // count and names: int i=0; unsigned int mc = 0; Method * mlist = class_copyMethodList(object_getClass(obj), &mc); for(i=0; i_vc2.isViewLoaded); }]; XCTAssertTrue(_vc1.isViewLoaded); XCTAssertTrue(_vc2.isViewLoaded); } - (void)testMergeOptions_shouldMergeWithChildOnly { [self.uut setReadyToReceiveCommands:true]; NSDictionary* mergeOptions = @{@"bottomTab": @{@"badge": @"Badge"}}; RNNNavigationOptions* firstChildOptions = [RNNNavigationOptions emptyOptions]; firstChildOptions.bottomTab.text = [Text withValue:@"First"]; RNNNavigationOptions* secondChildOptions = [RNNNavigationOptions emptyOptions]; secondChildOptions.bottomTab.text = [Text withValue:@"Second"]; RNNComponentViewController* firstChild = [RNNComponentViewController createWithComponentId:@"first" initialOptions:firstChildOptions]; RNNComponentViewController* secondChild = [RNNComponentViewController createWithComponentId:@"second" initialOptions:secondChildOptions]; RNNBottomTabsController* tabBarController = [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:[RNNNavigationOptions emptyOptions] defaultOptions:[[RNNNavigationOptions alloc] initEmptyOptions] presenter:[RNNBasePresenter new] bottomTabPresenter:[BottomTabPresenterCreator createWithDefaultOptions:[RNNNavigationOptions emptyOptions]] dotIndicatorPresenter:nil eventEmitter:_eventEmmiter childViewControllers:@[firstChild, secondChild] bottomTabsAttacher:nil]; OCMStub([self.controllerFactory createLayout:[OCMArg any]]).andReturn(tabBarController); [self.mainWindow setRootViewController:tabBarController]; [secondChild viewWillAppear:YES]; [self.uut mergeOptions:secondChild.layoutInfo.componentId options:mergeOptions completion:^{ }]; XCTAssertTrue([secondChild.tabBarItem.badgeValue isEqualToString:@"Badge"]); XCTAssertNil(firstChild.tabBarItem.badgeValue); XCTAssertTrue([firstChild.tabBarItem.title isEqualToString:@"First"]); XCTAssertTrue([secondChild.tabBarItem.title isEqualToString:@"Second"]); } - (void)testMergeOptions_shouldResolveTreeOptions { [self.uut setReadyToReceiveCommands:true]; NSDictionary* mergeOptions = @{@"bottomTab": @{@"badge": @"Badge"}}; RNNNavigationOptions* firstChildOptions = [RNNNavigationOptions emptyOptions]; RNNNavigationOptions* secondChildOptions = [RNNNavigationOptions emptyOptions]; secondChildOptions.bottomTab.text = [Text withValue:@"Second"]; RNNNavigationOptions* stackOptions = [RNNNavigationOptions emptyOptions]; stackOptions.bottomTab.text = [Text withValue:@"First"]; RNNComponentViewController* firstChild = [RNNComponentViewController createWithComponentId:@"first" initialOptions:firstChildOptions]; RNNStackController* stack = [[RNNStackController alloc] initWithLayoutInfo:nil creator:nil options:stackOptions defaultOptions:nil presenter:nil eventEmitter:nil childViewControllers:@[firstChild]]; RNNComponentViewController* secondChild = [RNNComponentViewController createWithComponentId:@"second" initialOptions:secondChildOptions]; RNNBottomTabsController* tabBarController = [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:[RNNNavigationOptions emptyOptions] defaultOptions:[[RNNNavigationOptions alloc] initEmptyOptions] presenter:[RNNBasePresenter new] bottomTabPresenter:[BottomTabPresenterCreator createWithDefaultOptions:[RNNNavigationOptions emptyOptions]] dotIndicatorPresenter:nil eventEmitter:_eventEmmiter childViewControllers:@[stack, secondChild] bottomTabsAttacher:nil]; OCMStub([self.controllerFactory createLayout:[OCMArg any]]).andReturn(tabBarController); [self.mainWindow setRootViewController:tabBarController]; [secondChild viewWillAppear:YES]; [self.uut mergeOptions:firstChild.layoutInfo.componentId options:mergeOptions completion:^{ }]; XCTAssertTrue([stack.tabBarItem.badgeValue isEqualToString:@"Badge"]); XCTAssertTrue([stack.tabBarItem.title isEqualToString:@"First"]); XCTAssertTrue([secondChild.tabBarItem.title isEqualToString:@"Second"]); } - (void)testShowModal_shouldShowAnimated { [self.uut setReadyToReceiveCommands:true]; self.vc1.options = [[RNNNavigationOptions alloc] initEmptyOptions]; self.vc1.options.animations.showModal.enable = [[Bool alloc] initWithBOOL:YES]; id mockedVC = [OCMockObject partialMockForObject:self.vc1]; OCMStub([self.controllerFactory createLayout:[OCMArg any]]).andReturn(mockedVC); [[self.modalManager expect] showModal:mockedVC animated:YES completion:[OCMArg any]]; [self.uut showModal:@{} commandId:@"showModal" completion:^(NSString *componentId) { }]; [self.modalManager verify]; } - (void)testPop_shouldRejectPromiseForInvalidComponentId { [self.uut setReadyToReceiveCommands:true]; XCTestExpectation *expectation = [self expectationWithDescription:@"Should invoke reject block"]; [self.uut pop:@"invalidComponentId" commandId:@"pop" mergeOptions:nil completion:^{ [expectation fulfill]; } rejection:^(NSString *code, NSString *message, NSError *error) { XCTAssert([code isEqualToString:@"1012"]); XCTAssert([message isEqualToString:@"Popping component failed - componentId 'invalidComponentId' not found"]); [expectation fulfill]; }]; [self waitForExpectationsWithTimeout:5 handler:nil]; } @end