diff --git a/e2e/Buttons.test.js b/e2e/Buttons.test.js index 5f73233730a..73d7f13c145 100644 --- a/e2e/Buttons.test.js +++ b/e2e/Buttons.test.js @@ -1,11 +1,11 @@ import Utils from './Utils'; import TestIDs from '../playground/src/testIDs'; -const { elementById, elementByLabel } = Utils; +const {elementById, elementByLabel} = Utils; describe('Buttons', () => { beforeEach(async () => { - await device.launchApp({ newInstance: true }); + await device.launchApp({newInstance: true}); await elementById(TestIDs.OPTIONS_TAB).tap(); await elementById(TestIDs.GOTO_BUTTONS_SCREEN).tap(); }); @@ -45,4 +45,10 @@ describe('Buttons', () => { await elementById(TestIDs.CHANGE_BUTTON_PROPS).tap(); await expect(elementByLabel('Three')).toBeVisible(); }); + + it('pop using back button', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.BACK_BUTTON).tap(); + await expect(elementByLabel('Buttons')).toBeVisible(); + }); }); diff --git a/lib/ios/RNNStackPresenter.m b/lib/ios/RNNStackPresenter.m index 299d1a5a8ed..56227cd0517 100644 --- a/lib/ios/RNNStackPresenter.m +++ b/lib/ios/RNNStackPresenter.m @@ -35,6 +35,7 @@ - (void)bindViewController:(UINavigationController *)boundViewController { - (void)componentDidAppear { [_topBarBackgroundReactView componentDidAppear]; + [_topBarPresenter componentDidAppear]; } - (void)componentDidDisappear { diff --git a/lib/ios/TopBarPresenter.m b/lib/ios/TopBarPresenter.m index ae9eee60730..ed152c4c25d 100644 --- a/lib/ios/TopBarPresenter.m +++ b/lib/ios/TopBarPresenter.m @@ -2,6 +2,8 @@ #import "UIImage+tint.h" #import "RNNFontAttributesCreator.h" #import "UIColor+RNNUtils.h" +#import "UIViewController+LayoutProtocol.h" +#import "UINavigationController+RNNOptions.h" @implementation TopBarPresenter @@ -112,6 +114,11 @@ - (void)setLargeTitleAttributes:(RNNLargeTitleOptions *)largeTitleOptions { } } +- (void)componentDidAppear { + NSString* backButtonTestID = [self.navigationController.topViewController.resolveOptionsWithDefault.topBar.backButton.testID getWithDefaultValue:nil]; + [self.navigationController setBackButtonTestID:backButtonTestID]; +} + - (void)setBackButtonOptions:(RNNBackButtonOptions *)backButtonOptions { UIImage* icon = [backButtonOptions.icon getWithDefaultValue:nil]; UIColor* color = [backButtonOptions.color getWithDefaultValue:nil]; @@ -119,12 +126,9 @@ - (void)setBackButtonOptions:(RNNBackButtonOptions *)backButtonOptions { BOOL showTitle = [backButtonOptions.showTitle getWithDefaultValue:YES]; NSString* fontFamily = [backButtonOptions.fontFamily getWithDefaultValue:nil]; NSNumber* fontSize = [backButtonOptions.fontSize getWithDefaultValue:nil]; - NSString* testID = [backButtonOptions.testID getWithDefaultValue:nil]; - NSArray* stackChildren = self.navigationController.viewControllers; - UIViewController *lastViewControllerInStack = stackChildren.count > 1 ? stackChildren[stackChildren.count - 2] : self.navigationController.topViewController; + UIViewController *previousViewControllerInStack = self.previousViewControllerInStack; UIBarButtonItem *backItem = [UIBarButtonItem new]; - backItem.accessibilityIdentifier = testID; icon = color ? [[icon withTintColor:color] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] @@ -132,7 +136,7 @@ - (void)setBackButtonOptions:(RNNBackButtonOptions *)backButtonOptions { [self setBackIndicatorImage:icon withColor:color]; if (showTitle) { - backItem.title = title ? title : lastViewControllerInStack.navigationItem.title; + backItem.title = title ? title : previousViewControllerInStack.navigationItem.title; } else { backItem.title = @""; } @@ -145,7 +149,13 @@ - (void)setBackButtonOptions:(RNNBackButtonOptions *)backButtonOptions { [backItem setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys: [UIFont fontWithName:fontFamily size:resolvedFontSize], NSFontAttributeName, nil] forState:UIControlStateHighlighted]; } - lastViewControllerInStack.navigationItem.backBarButtonItem = backItem; + previousViewControllerInStack.navigationItem.backBarButtonItem = backItem; +} + +- (UIViewController *)previousViewControllerInStack { + NSArray* stackChildren = self.navigationController.viewControllers; + UIViewController *previousViewControllerInStack = stackChildren.count > 1 ? stackChildren[stackChildren.count - 2] : self.navigationController.topViewController; + return previousViewControllerInStack; } - (BOOL)transparent { diff --git a/lib/ios/UINavigationController+RNNOptions.h b/lib/ios/UINavigationController+RNNOptions.h index 46388cf61a4..0ff0267eef1 100644 --- a/lib/ios/UINavigationController+RNNOptions.h +++ b/lib/ios/UINavigationController+RNNOptions.h @@ -16,4 +16,6 @@ - (void)setNavigationBarClipsToBounds:(BOOL)clipsToBounds; +- (void)setBackButtonTestID:(NSString *)testID; + @end diff --git a/lib/ios/UINavigationController+RNNOptions.m b/lib/ios/UINavigationController+RNNOptions.m index bda2673f526..9be81995c4a 100644 --- a/lib/ios/UINavigationController+RNNOptions.m +++ b/lib/ios/UINavigationController+RNNOptions.m @@ -1,5 +1,6 @@ #import "UINavigationController+RNNOptions.h" #import "RNNFontAttributesCreator.h" +#import "UIView+Utils.h" const NSInteger BLUR_TOPBAR_TAG = 78264802; @@ -58,6 +59,12 @@ - (void)setNavigationBarClipsToBounds:(BOOL)clipsToBounds { self.navigationBar.clipsToBounds = clipsToBounds; } +- (void)setBackButtonTestID:(NSString *)testID { + UIView* navigationBarContentView = [self.navigationBar findChildByClass:NSClassFromString(@"_UINavigationBarContentView")]; + UIView* barButton = [navigationBarContentView findChildByClass:NSClassFromString(@"_UIButtonBarButton")]; + if (barButton) barButton.accessibilityIdentifier = testID; +} + - (CGFloat)getTopBarHeight { return self.navigationBar.frame.size.height; } diff --git a/lib/ios/Utils/UIView+Utils.h b/lib/ios/Utils/UIView+Utils.h index 903d4a3339a..952a0537da8 100644 --- a/lib/ios/Utils/UIView+Utils.h +++ b/lib/ios/Utils/UIView+Utils.h @@ -13,6 +13,4 @@ typedef NS_ENUM(NSInteger, ViewType) { - (ViewType)viewType; -- (void)layout:(CGFloat)p; - @end diff --git a/lib/ios/Utils/UIView+Utils.m b/lib/ios/Utils/UIView+Utils.m index 9839e195a76..350aaf1d036 100644 --- a/lib/ios/Utils/UIView+Utils.m +++ b/lib/ios/Utils/UIView+Utils.m @@ -11,10 +11,6 @@ - (UIView *)findChildByClass:(id)clazz { return nil; } -- (void)layout:(CGFloat)p { - -} - - (ViewType)viewType { if ([self isKindOfClass:[RCTImageView class]]) { return ViewTypeImage; diff --git a/playground/ios/NavigationTests/RNNStackControllerTest.m b/playground/ios/NavigationTests/RNNStackControllerTest.m index d5e2a2a0721..9b1609d3eaa 100644 --- a/playground/ios/NavigationTests/RNNStackControllerTest.m +++ b/playground/ios/NavigationTests/RNNStackControllerTest.m @@ -3,6 +3,7 @@ #import #import #import "RNNTestRootViewCreator.h" +#import "RNNComponentViewController+Utils.h" @interface RNNStackControllerTest : XCTestCase @@ -210,6 +211,17 @@ - (void)testMergeChildOptionsShouldNotUpdatePresenterForInvisibleChild { [_presenter verify]; } +- (void)testOnChildWillAppear_shouldSetBackButtonTestID { + RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initEmptyOptions]; + options.topBar.backButton.testID = [Text withValue:@"TestID"]; + RNNComponentViewController* pushedController = [RNNComponentViewController createWithComponentId:@"pushedController"]; + pushedController.options.topBar.backButton.testID = [Text withValue:@"TestID"]; + [[[UIApplication sharedApplication] keyWindow] setRootViewController:_uut]; + [_uut pushViewController:pushedController animated:NO]; + [pushedController viewDidAppear:YES]; + XCTAssertTrue([[[_uut.navigationBar.subviews[2] subviews][0] valueForKey:@"accessibilityIdentifier"] isEqualToString:@"TestID"]); +} + - (RNNStackController *)createNavigationControllerWithOptions:(RNNNavigationOptions *)options { RNNStackController* nav = [[RNNStackController alloc] initWithLayoutInfo:nil creator:_creator options:options defaultOptions:nil presenter:[[RNNStackPresenter alloc] init] eventEmitter:nil childViewControllers:@[_vc1]]; return nav; diff --git a/playground/ios/NavigationTests/TopBarAppearancePresenterTest.m b/playground/ios/NavigationTests/TopBarAppearancePresenterTest.m index 88eb3aaab51..fef4afa1d36 100644 --- a/playground/ios/NavigationTests/TopBarAppearancePresenterTest.m +++ b/playground/ios/NavigationTests/TopBarAppearancePresenterTest.m @@ -19,8 +19,8 @@ @implementation TopBarAppearancePresenterTest { - (void)setUp { [super setUp]; _componentViewController = [RNNComponentViewController createWithComponentId:@"componentId"]; - _stack = [[RNNStackController alloc] initWithLayoutInfo:nil creator:nil options:[[RNNNavigationOptions alloc] initEmptyOptions] defaultOptions:[[RNNNavigationOptions alloc] initEmptyOptions] presenter:_uut eventEmitter:nil childViewControllers:@[_componentViewController]]; _uut = [[TopBarAppearancePresenter alloc] initWithNavigationController:_stack]; + _stack = [[RNNStackController alloc] initWithLayoutInfo:nil creator:nil options:[[RNNNavigationOptions alloc] initEmptyOptions] defaultOptions:[[RNNNavigationOptions alloc] initEmptyOptions] presenter:_uut eventEmitter:nil childViewControllers:@[_componentViewController]]; } - (void)testMergeOptions_shouldMergeWithDefault { @@ -36,14 +36,4 @@ - (void)testMergeOptions_shouldMergeWithDefault { XCTAssertEqual(font.pointSize, 21); } -- (void)testApplyOptions_shouldSetBackButtonTestID { - RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initEmptyOptions]; - options.topBar.backButton.testID = [Text withValue:@"TestID"]; - - [_uut applyOptions:options.topBar]; - XCTAssertTrue([_componentViewController.navigationItem.backBarButtonItem.accessibilityIdentifier isEqualToString:@"TestID"]); -} - - - @end diff --git a/playground/ios/NavigationTests/utils/RNNComponentViewController+Utils.m b/playground/ios/NavigationTests/utils/RNNComponentViewController+Utils.m index f8a8a7a8606..3270b3afa3e 100644 --- a/playground/ios/NavigationTests/utils/RNNComponentViewController+Utils.m +++ b/playground/ios/NavigationTests/utils/RNNComponentViewController+Utils.m @@ -10,7 +10,7 @@ + (RNNComponentViewController *)createWithComponentId:(NSString *)componentId in } + (RNNComponentViewController *)createWithComponentId:(NSString *)componentId { - return [self createWithComponentId:componentId initialOptions:nil]; + return [self createWithComponentId:componentId initialOptions:RNNNavigationOptions.emptyOptions]; } @end diff --git a/playground/src/screens/PushedScreen.tsx b/playground/src/screens/PushedScreen.tsx index 2d45666e766..46c0dfeffcf 100644 --- a/playground/src/screens/PushedScreen.tsx +++ b/playground/src/screens/PushedScreen.tsx @@ -21,6 +21,7 @@ const { SET_STACK_ROOT_BUTTON, PUSH_OPTIONS_BUTTON, HIDE_PREVIOUS_SCREEN_TOP_BAR, + BACK_BUTTON, } = testIDs; interface Props extends NavigationComponentProps { @@ -41,6 +42,9 @@ export default class PushedScreen extends React.Component { text: 'single', testID: TOP_BAR_BTN, }, + backButton: { + testID: BACK_BUTTON, + }, }, }; } diff --git a/playground/src/testIDs.ts b/playground/src/testIDs.ts index e4fc4b6261c..a391af1f284 100644 --- a/playground/src/testIDs.ts +++ b/playground/src/testIDs.ts @@ -40,6 +40,7 @@ const testIDs = { TOP_BAR_BTN: 'TOP_BAR_BUTTON', CUSTOM_BACK_BTN: 'CUSTOM_BACK_BUTTON', PUSH_CUSTOM_BACK_BTN: 'PUSH_CUSTOM_BACK_BTN', + BACK_BUTTON: 'BACK_BUTTON', SWITCH_TAB_BY_INDEX_BTN: 'SWITCH_TAB_BY_INDEX_BTN', SWITCH_TAB_BY_COMPONENT_ID_BTN: 'SWITCH_TAB_BY_COMPONENT_ID_BTN', PUSHED_BOTTOM_TABS: 'PUSHED_BOTTOM_TABS', diff --git a/website/api/options-backButton.mdx b/website/api/options-backButton.mdx index 3fa6daae80c..92bbaa18bd2 100644 --- a/website/api/options-backButton.mdx +++ b/website/api/options-backButton.mdx @@ -9,12 +9,13 @@ Controls the back button styling. ```js const options = { topBar: { - backButton: {} - } -} + backButton: {}, + }, +}; ``` ### `color` + Change the back button color. This will change the text color as well. | Type | Required | Platform | @@ -22,6 +23,7 @@ Change the back button color. This will change the text color as well. | color | No | Both | ### `icon` + Change the default back button icon. | Type | Required | Platform | @@ -29,6 +31,7 @@ Change the default back button icon. | number | No | Both | ### `showTitle` + Show or hide the text displayed next to the back button. | Type | Required | Platform | @@ -36,6 +39,7 @@ Show or hide the text displayed next to the back button. | number | No | iOS | ### `title` + Change the text displayed next to the title. Usually the back button shows the title of the previous screen. | Type | Required | Platform | @@ -43,8 +47,17 @@ Change the text displayed next to the title. Usually the back button shows the t | string | No | iOS | ### `visible` + Hide or show the back button. | Type | Required | Platform | | ------- | -------- | -------- | | boolean | No | Both | + +### `testID` + +Used to interact with the back button in e2e tests. + +| Type | Required | Platform | +| ------ | -------- | -------- | +| string | No | Both |