Skip to content

Commit

Permalink
fix(ios, afterInitialTab): ensure initial tab mounts before other tab…
Browse files Browse the repository at this point in the history
…s. (#7890)

* fix(ios, afterInitialTab): ensure initial tab mounts before other tabs.

Updated `BottomTabsAfterInitialTabAttacher` to asynchronously attach other tabs
 after the initial tab's `componentDidMount` is called.

* test(e2e): add test for mounted screens order (attach after initial tab)
  • Loading branch information
asafkorem committed Jun 25, 2024
1 parent 6439f68 commit 8a955b8
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 4 deletions.
6 changes: 6 additions & 0 deletions e2e/BottomTabs.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ describe('BottomTabs', () => {
await expect(elementByLabel('First Tab')).toBeVisible();
});

it.e2e('should mount first tab first', async () => {
await expect(elementById(TestIDs.MOUNTED_SCREENS_TEXT)).toHaveText(
'Mounted screens: FirstBottomTabScreen, SecondBottomTabScreen'
);
});

it('switch to tab by index', async () => {
await elementById(TestIDs.SWITCH_TAB_BY_INDEX_BTN).tap();
await expect(elementByLabel('First Tab')).toBeNotVisible();
Expand Down
2 changes: 2 additions & 0 deletions lib/ios/BottomTabsAfterInitialTabAttacher.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ - (void)attach:(UITabBarController *)bottomTabsController {
[bottomTabsController.selectedViewController setReactViewReadyCallback:^{
[bottomTabsController readyForPresentation];
for (UIViewController *viewController in bottomTabsController.deselectedViewControllers) {
dispatch_async(dispatch_get_main_queue(), ^{
[viewController render];
});
}
}];

Expand Down
17 changes: 15 additions & 2 deletions playground/ios/NavigationTests/RNNCommandsHandlerTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -554,8 +554,21 @@ - (void)testSetRoot_withBottomTabsAttachModeAfterInitialTab {
}];

[self waitForExpectationsWithTimeout:10 handler:nil];
XCTAssertTrue(_vc1.isViewLoaded);
XCTAssertTrue(_vc2.isViewLoaded);

XCTAssertTrue(self->_vc1.isViewLoaded);

// Make sure the view is not loaded until the next main run loop.
XCTAssertFalse(self->_vc2.isViewLoaded);


// Wait for the next main run-loop.
XCTestExpectation *viewLoadedExpectation = [self expectationWithDescription:@"Wait for _vc2.isViewLoaded"];
dispatch_async(dispatch_get_main_queue(), ^{
XCTAssertTrue(self->_vc2.isViewLoaded);
[viewLoadedExpectation fulfill];
});

[self waitForExpectationsWithTimeout:1 handler:nil];
}

- (void)testSetRoot_withAnimation {
Expand Down
37 changes: 35 additions & 2 deletions playground/src/screens/FirstBottomTabScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
import React from 'react';
import React, { Component } from 'react';
import { NavigationProps, Options } from 'react-native-navigation';
import Root from '../components/Root';
import Button from '../components/Button';
import Navigation from './../services/Navigation';
import Screens from './Screens';
import { component } from '../commons/Layouts';
import testIDs from '../testIDs';
import { Text } from 'react-native';

export class MountedBottomTabScreensState {
static mountedBottomTabScreens: string[] = [];
static callback: (mountedBottomTabScreens: string[]) => void = () => {};

static addScreen(screen: string) {
this.mountedBottomTabScreens.push(screen);
this.callback(this.mountedBottomTabScreens);
}
}

const {
SWITCH_TAB_BY_INDEX_BTN,
Expand All @@ -16,9 +27,14 @@ const {
SHOW_TABS_BTN,
HIDE_TABS_PUSH_BTN,
FIRST_TAB_BAR_BUTTON,
MOUNTED_SCREENS_TEXT,
} = testIDs;

export default class FirstBottomTabScreen extends React.Component<NavigationProps> {
interface NavigationState {
mountedBottomTabScreens: string[];
}

export default class FirstBottomTabScreen extends Component<NavigationProps, NavigationState> {
static options(): Options {
return {
layout: {
Expand All @@ -38,6 +54,19 @@ export default class FirstBottomTabScreen extends React.Component<NavigationProp
};
}

constructor(props: NavigationProps) {
super(props);
this.state = { mountedBottomTabScreens: [] };

MountedBottomTabScreensState.callback = (mountedBottomTabScreens: string[]) => {
this.setState({ mountedBottomTabScreens: mountedBottomTabScreens });
};
}

componentDidMount() {
MountedBottomTabScreensState.addScreen('FirstBottomTabScreen');
}

badgeVisible = true;
bottomTabPressedListener = Navigation.events().registerBottomTabPressedListener((event) => {
if (event.tabIndex == 2) {
Expand Down Expand Up @@ -71,6 +100,10 @@ export default class FirstBottomTabScreen extends React.Component<NavigationProp
/>
<Button label="Push" onPress={this.push} />
<Button label="Add border and shadow" onPress={this.modifyBottomTabs} />

<Text testID={MOUNTED_SCREENS_TEXT}>
Mounted screens: {this.state.mountedBottomTabScreens.join(', ')}
</Text>
</Root>
);
}
Expand Down
5 changes: 5 additions & 0 deletions playground/src/screens/SecondBottomTabScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Screens from './Screens';
import Navigation from './../services/Navigation';
import { stack, component } from './../commons/Layouts';
import testIDs from '../testIDs';
import { MountedBottomTabScreensState } from './FirstBottomTabScreen';

const {
SIDE_MENU_INSIDE_BOTTOM_TABS_BTN,
Expand Down Expand Up @@ -40,6 +41,10 @@ export default class SecondBottomTabScreen extends React.Component<NavigationPro
};
}

componentDidMount() {
MountedBottomTabScreensState.addScreen('SecondBottomTabScreen');
}

render() {
return (
<Root componentId={this.props.componentId}>
Expand Down
1 change: 1 addition & 0 deletions playground/src/testIDs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ const testIDs = {
TOGGLE_REACT_DECLARED_MODAL: 'TOGGLE_REACT_DECLARED_MODAL',
REPLACE_TAB_TEST_ID: 'REPLACE_TAB_TEST_ID',
REPLACED_TAB: 'REPLACED_TAB',
MOUNTED_SCREENS_TEXT: 'MOUNTED_SCREENS_TEXT',

//External Component Buttons
EXTERNAL_DISMISS_MODAL_BTN: 'EXTERNAL_DISMISS_MODAL_BTN',
Expand Down

0 comments on commit 8a955b8

Please sign in to comment.