Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Migrate example apps to use react-navigation #2084

Merged
merged 31 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
6936e4e
Add better algorithm for resolving paths in resolveRequest
tboba Mar 27, 2024
3df2015
Apply better metro algorithm for example, update typescript
tboba Mar 27, 2024
6d34fdf
Update @types/react to newer version, migrate App.tsx from Example
tboba Mar 27, 2024
24c1585
Move example to use @react-navigation/native-stack
tboba Mar 28, 2024
ba9f6f2
Add headerTitleAlign option, add informative toasts
tboba Mar 28, 2024
514c523
Update detox, match code to pass CI
tboba Mar 28, 2024
b864e34
Revert own configuration from detoxrc
tboba Mar 28, 2024
5c9369d
Add command to install submodules
tboba Mar 28, 2024
70a7447
Change command to pipe execution
tboba Mar 28, 2024
067ec49
Add reinstall step
tboba Mar 29, 2024
115e0f4
Add continue-on-error declarations
tboba Mar 29, 2024
1f2b08c
Downgrade detox version
tboba Mar 29, 2024
e9877b2
Change command to retry
tboba Mar 29, 2024
4dccd5b
Add timeout_minutes
tboba Mar 29, 2024
34f06ba
Remove flipper
tboba Mar 29, 2024
05918c6
Change yarn.lock
tboba Mar 29, 2024
99d3df4
Merge branch 'main' into @tboba/improve-examples
tboba Apr 11, 2024
70ba981
Add changes from react-navigation, yarn.locki
tboba Apr 12, 2024
048e857
Remove duplicated submodule script
tboba Apr 15, 2024
ff6797b
Remove unnecessary events from events.e2e.ts
tboba Apr 15, 2024
2f73d01
Update imports in TestExamples
tboba Apr 15, 2024
67ecf60
Move TVOSExample to use react-navigation, correct some imports
tboba Apr 15, 2024
1e7ec0a
Try to comment using test butler
tboba Apr 16, 2024
45c6b34
Try to add awaits
tboba Apr 16, 2024
6e825e5
Merge branch 'main' into @tboba/improve-examples
tboba Apr 18, 2024
67aa18b
Change retry to normal commands again
tboba Apr 18, 2024
4877491
Merge branch 'main' into @tboba/improve-examples
tboba May 6, 2024
178c6e2
Sync all metro configs of examples
tboba May 6, 2024
7c4c93f
Make E2E events great again
tboba May 6, 2024
df1e30e
Move 'using header button' to other place in events.e2e.ts
tboba May 6, 2024
204ab1a
Force RTL mode in RTL examples
tboba May 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/android-e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,14 @@ jobs:
- name: Install root node dependencies
run: yarn install && yarn submodules
- name: Install node dependencies
id: install_deps
working-directory: ${{ env.WORKING_DIRECTORY }}
continue-on-error: true
run: yarn install
- if: steps.install_deps.outcome == 'failure'
name: Reinstall node dependencies
working-directory: ${{ env.WORKING_DIRECTORY }}
run: yarn
kkafar marked this conversation as resolved.
Show resolved Hide resolved
- name: Build app
working-directory: ${{ env.WORKING_DIRECTORY }}
run: yarn build-e2e-android
Expand Down
7 changes: 2 additions & 5 deletions Example/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { StackNavigationProp } from '@react-navigation/stack';
import { createNativeStackNavigator } from 'react-native-screens/native-stack';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import RNRestart from 'react-native-restart';

import { ListItem, SettingsSwitch } from './src/shared';
Expand Down Expand Up @@ -161,10 +161,7 @@ const ExampleApp = (): JSX.Element => (
<GestureHandlerRootView style={{ flex: 1 }}>
<GestureDetectorProvider>
<NavigationContainer>
<Stack.Navigator
screenOptions={{
direction: I18nManager.isRTL ? 'rtl' : 'ltr',
}}>
<Stack.Navigator>
<Stack.Screen
name="Main"
options={{ title: '📱 React Native Screens Examples' }}
Expand Down
68 changes: 36 additions & 32 deletions Example/e2e/examplesTests/bottomTabs.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,75 +12,79 @@ describe('Bottom tabs and native stack', () => {
await element(by.id('root-screen-example-BottomTabsAndStack')).tap();

await expect(
element(by.id('bottom-tabs-more-details-button'))
element(by.id('bottom-tabs-A-more-details-button'))
).toBeVisible();
});

it('should go to details screen', async () => {
await element(by.id('root-screen-example-BottomTabsAndStack')).tap();
await element(by.id('bottom-tabs-more-details-button')).tap();
await expect(element(by.id('bottom-tabs-more-details-button'))).toHaveLabel(
'More details 1'
);
await element(by.id('bottom-tabs-A-more-details-button')).tap();
await expect(
element(by.id('bottom-tabs-A-more-details-button'))
).toHaveLabel('More details 1');
});

it('should go to details screen and back', async () => {
await element(by.id('root-screen-example-BottomTabsAndStack')).tap();
await element(by.id('bottom-tabs-more-details-button')).tap();
await expect(element(by.id('bottom-tabs-more-details-button'))).toHaveLabel(
'More details 1'
);
await element(by.id('bottom-tabs-A-more-details-button')).tap();
await expect(
element(by.id('bottom-tabs-A-more-details-button'))
).toHaveLabel('More details 1');
if (device.getPlatform() === 'ios') {
await element(by.type('_UIButtonBarButton')).tap();
} else {
await device.pressBack();
}
await expect(element(by.id('bottom-tabs-more-details-button'))).toHaveLabel(
'More details 0'
);
await expect(
element(by.id('bottom-tabs-A-more-details-button'))
).toHaveLabel('More details 0');
});

it('should go between tabs', async () => {
await element(by.id('root-screen-example-BottomTabsAndStack')).tap();

await element(by.id('bottom-tabs-B-tab')).tap();
await expect(element(by.id('bottom-tabs-header-right-id'))).toHaveText('B');
await expect(element(by.id('bottom-tabs-B-header-right-id'))).toHaveText(
'B'
);

await element(by.id('bottom-tabs-A-tab')).tap();
await expect(element(by.id('bottom-tabs-header-right-id'))).toHaveText('A');
await expect(element(by.id('bottom-tabs-A-header-right-id'))).toHaveText(
'A'
);
});

it('should go to first screen on double tap on a tab', async () => {
await element(by.id('root-screen-example-BottomTabsAndStack')).tap();

await element(by.id('bottom-tabs-more-details-button')).tap();
await expect(element(by.id('bottom-tabs-more-details-button'))).toHaveLabel(
'More details 1'
);
await element(by.id('bottom-tabs-A-more-details-button')).tap();
await expect(
element(by.id('bottom-tabs-A-more-details-button'))
).toHaveLabel('More details 1');

await element(by.id('bottom-tabs-A-tab')).multiTap(2);
await expect(element(by.id('bottom-tabs-more-details-button'))).toHaveLabel(
'More details 0'
);
await expect(
element(by.id('bottom-tabs-A-more-details-button'))
).toHaveLabel('More details 0');
});

it('should keep stack state on tab change', async () => {
await element(by.id('root-screen-example-BottomTabsAndStack')).tap();

await element(by.id('bottom-tabs-more-details-button')).tap();
await element(by.id('bottom-tabs-more-details-button')).tap();
await expect(element(by.id('bottom-tabs-more-details-button'))).toHaveLabel(
'More details 2'
);
await element(by.id('bottom-tabs-A-more-details-button')).tap();
await element(by.id('bottom-tabs-A-more-details-button')).tap();
await expect(
element(by.id('bottom-tabs-A-more-details-button'))
).toHaveLabel('More details 2');

await element(by.id('bottom-tabs-B-tab')).tap();
await expect(element(by.id('bottom-tabs-more-details-button'))).toHaveLabel(
'More details 0'
);
await expect(
element(by.id('bottom-tabs-B-more-details-button'))
).toHaveLabel('More details 0');
await element(by.id('bottom-tabs-A-tab')).tap();

await expect(element(by.id('bottom-tabs-more-details-button'))).toHaveLabel(
'More details 2'
);
await expect(
element(by.id('bottom-tabs-A-more-details-button'))
).toHaveLabel('More details 2');
});
});
143 changes: 56 additions & 87 deletions Example/e2e/examplesTests/events.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,49 @@
import { device, expect, element, by } from 'detox';

const pressBack = async () => {
if (device.getPlatform() === 'android') {
await device.pressBack();
} else if (device.getPlatform() === 'ios') {
await element(by.traits(['button']))
.atIndex(0)
.tap();
}
};

const awaitClassicalEventBehavior = async () => {
if (device.getPlatform() === 'ios') {
await expect(
element(by.text('9. Chats | transitionStart | closing'))
).toExist();
await expect(
element(by.text('10. Privacy | transitionStart | closing'))
).toExist();
await expect(
element(by.text('11. Main | transitionStart | opening'))
).toExist();
await expect(
element(by.text('12. Chats | transitionEnd | closing'))
).toExist();
await expect(
element(by.text('13. Privacy | transitionEnd | closing'))
).toExist();
await expect(element(by.text('14. Privacy | beforeRemove'))).toExist();
await expect(element(by.text('15. Chats | beforeRemove'))).toExist();
await expect(
element(by.text('16. Main | transitionEnd | opening'))
).toExist();
} else {
await expect(element(by.text('9. Privacy | beforeRemove'))).toExist();
await expect(element(by.text('10. Chats | beforeRemove'))).toExist();
await expect(
element(by.text('11. Main | transitionStart | opening'))
).toExist();
await expect(
element(by.text('12. Main | transitionEnd | opening'))
).toExist();
}
};

describe('Events', () => {
beforeEach(async () => {
await device.reloadReactNative();
Expand Down Expand Up @@ -39,24 +83,7 @@ describe('Events', () => {
).tap();
}

await expect(
element(by.text('9. Chats | transitionStart | closing'))
).toExist();
await expect(
element(by.text('10. Privacy | transitionStart | closing'))
).toExist();
await expect(
element(by.text('11. Main | transitionStart | opening'))
).toExist();
await expect(
element(by.text('12. Chats | transitionEnd | closing'))
).toExist();
await expect(
element(by.text('13. Privacy | transitionEnd | closing'))
).toExist();
await expect(
element(by.text('14. Main | transitionEnd | opening'))
).toExist();
await awaitClassicalEventBehavior();
});

it('should use "none" animation, go back from Chats using header button and run opening & closing events in correct order ', async () => {
Expand All @@ -75,24 +102,7 @@ describe('Events', () => {
).tap();
}

await expect(
element(by.text('9. Chats | transitionStart | closing'))
).toExist();
await expect(
element(by.text('10. Privacy | transitionStart | closing'))
).toExist();
await expect(
element(by.text('11. Main | transitionStart | opening'))
).toExist();
await expect(
element(by.text('12. Chats | transitionEnd | closing'))
).toExist();
await expect(
element(by.text('13. Privacy | transitionEnd | closing'))
).toExist();
await expect(
element(by.text('14. Main | transitionEnd | opening'))
).toExist();
await awaitClassicalEventBehavior();
});

it('should use "slide_from_bottom" animation, go to Chats and run opening & closing events in correct order ', async () => {
Expand Down Expand Up @@ -139,83 +149,42 @@ describe('Events', () => {
).tap();
}

await expect(
element(by.text('9. Chats | transitionStart | closing'))
).toExist();
await expect(
element(by.text('10. Privacy | transitionStart | closing'))
).toExist();
await expect(
element(by.text('11. Main | transitionStart | opening'))
).toExist();
await expect(
element(by.text('12. Chats | transitionEnd | closing'))
).toExist();
await expect(
element(by.text('13. Privacy | transitionEnd | closing'))
).toExist();
await expect(
element(by.text('14. Main | transitionEnd | opening'))
).toExist();
await awaitClassicalEventBehavior();
});

it('[Android] should go back from Chats using native way and run opening & closing events in correct order ', async () => {
// swipe to go back doesn't seem to work on iOS
if (device.getPlatform() !== 'android') return;

it('should go back from Chats using native way and run opening & closing events in correct order ', async () => {
await element(by.id('root-screen-playground-Events')).tap();

await element(by.id('events-go-to-chats')).tap();

await device.pressBack();
await pressBack();

await expect(
element(by.text('9. Main | transitionStart | opening'))
).toExist();
await expect(
element(by.text('10. Main | transitionEnd | opening'))
).toExist();
await awaitClassicalEventBehavior();
});

it('[Android] should use "none" animation, go back from Chats using native way and run opening & closing events in correct order ', async () => {
// swipe to go back doesn't seem to work on iOS
if (device.getPlatform() !== 'android') return;

it('should use "none" animation, go back from Chats using native way and run opening & closing events in correct order ', async () => {
await element(by.id('root-screen-playground-Events')).tap();

await element(by.id('events-stack-animation-picker')).tap();
await element(by.id('stack-animation-none')).tap();

await element(by.id('events-go-to-chats')).tap();

await device.pressBack();
await pressBack();

await expect(
element(by.text('9. Main | transitionStart | opening'))
).toExist();
await expect(
element(by.text('10. Main | transitionEnd | opening'))
).toExist();
await awaitClassicalEventBehavior();
});

it('[Android] should use "slide_from_bottom" animation, go back from Chats using native way and run opening & closing events in correct order ', async () => {
// swipe to go back doesn't seem to work on iOS
if (device.getPlatform() !== 'android') return;

it('should use "slide_from_bottom" animation, go back from Chats using native way and run opening & closing events in correct order ', async () => {
await element(by.id('root-screen-playground-Events')).tap();

await element(by.id('events-stack-animation-picker')).tap();
await element(by.id('stack-animation-slide_from_bottom')).tap();

await element(by.id('events-go-to-chats')).tap();

await device.pressBack();
await pressBack();

await expect(
element(by.text('9. Main | transitionStart | opening'))
).toExist();
await expect(
element(by.text('10. Main | transitionEnd | opening'))
).toExist();
await awaitClassicalEventBehavior();
});
});
Loading
Loading