-
-
Notifications
You must be signed in to change notification settings - Fork 575
chore(iOS, Fabric): add tests for header interactions #2848
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
Changes from 2 commits
07256da
f505d72
76c1d9f
d1c0127
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,267 @@ | ||
import { device, expect, element, by } from 'detox'; | ||
import { describeIfiOS } from '../e2e-utils'; | ||
|
||
const expectBackButtonMenuWithTheSameLabel = async (text: string) => { | ||
await element(by.text(text)).longPressAndDrag(700, NaN, NaN, element(by.text('VOID')), NaN, NaN, "fast", 0); // open | ||
await waitFor(element(by.type('_UIContextMenuView'))).toBeVisible(); | ||
await expect(element(by.text(text).withAncestor(by.type('_UIContextMenuView')))).toBeVisible(); | ||
await element(by.text('VOID')).tap(); // close | ||
await waitFor(element(by.type('_UIContextMenuView'))).not.toBeVisible(); | ||
await waitFor(element(by.text(text)).atIndex(1)).not.toExist(); | ||
await expect(element(by.text(text)).atIndex(0)).toBeVisible(); | ||
}; | ||
|
||
const expectBackButtonMenuWithDifferentLabels = async (buttonTitle: string, backButtonMenuLabel: string) => { | ||
await element(by.text(buttonTitle)).longPressAndDrag(700, NaN, NaN, element(by.text('VOID')), NaN, NaN, "fast", 0); // open | ||
await waitFor(element(by.type('_UIContextMenuView'))).toBeVisible(); | ||
await expect(element(by.text(backButtonMenuLabel).withAncestor(by.type('_UIContextMenuView')))).toBeVisible(); | ||
await element(by.text('VOID')).tap(); // close | ||
await waitFor(element(by.type('_UIContextMenuView'))).not.toBeVisible(); | ||
await waitFor(element(by.text(backButtonMenuLabel))).not.toBeVisible(); | ||
await expect(element(by.text(buttonTitle))).toBeVisible(); | ||
}; | ||
|
||
const expectBackButtonMenuIconAndLabel = async (buttonId: string, backButtonMenuLabel: string) => { | ||
await element(by.id(buttonId)).longPressAndDrag(700, NaN, NaN, element(by.text('VOID')), NaN, NaN, "fast", 0); // open | ||
await expect(element(by.text(backButtonMenuLabel).withAncestor(by.type('_UIContextMenuView')))).toBeVisible(); | ||
await waitFor(element(by.type('_UIContextMenuView'))).toBeVisible(); | ||
await element(by.text('VOID')).tap(); // close | ||
await waitFor(element(by.type('_UIContextMenuView'))).not.toBeVisible(); | ||
}; | ||
|
||
const expectBackButtonMenuToNotExistOnLabel = async (text: string) => { | ||
await element(by.text(text)).longPressAndDrag(700, NaN, NaN, element(by.text('VOID')), NaN, NaN, "fast", 0); // open | ||
await expect(element(by.type('_UIContextMenuView'))).not.toExist(); | ||
}; | ||
|
||
|
||
describeIfiOS('Test2809', () => { | ||
beforeAll(async () => { | ||
await device.reloadReactNative(); | ||
}); | ||
|
||
it('Test2809 should exist', async () => { | ||
await waitFor(element(by.id('root-screen-tests-Test2809'))) | ||
.toBeVisible() | ||
.whileElement(by.id('root-screen-examples-scrollview')) | ||
.scroll(600, 'down', NaN, 0.85); | ||
|
||
await expect(element(by.id('root-screen-tests-Test2809'))).toBeVisible(); | ||
await element(by.id('root-screen-tests-Test2809')).tap(); | ||
}); | ||
|
||
describe('backButtonMenuEnabled: true', () => { | ||
describe('backButtonDisplayMode: default', () => { | ||
it('with default text', async () => { | ||
await element(by.text('EnabledDefaultDefaultText')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.text('First'))).toBeVisible(); | ||
await expectBackButtonMenuWithTheSameLabel('First'); // Check if backButtonMenu works | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
}); | ||
|
||
it('with custom text', async () => { | ||
await element(by.text('EnabledDefaultCustomText')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.text('Custom'))).toBeVisible(); | ||
await expectBackButtonMenuWithTheSameLabel('Custom'); // Check if backButtonMenu works | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
}); | ||
|
||
// We don't check if the styles are applied, I think that it could be flaky, but it can be done | ||
// using element(by.type('UIButtonLabel')).getAttributes() and looking at bounds. The values there | ||
// doesn't match the ones in the code exactly (I think some padding is added), so I don't think we should do that. | ||
it('with styled text', async () => { | ||
await element(by.text('EnabledDefaultStyledText')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.text('First'))).toBeVisible(); | ||
await expectBackButtonMenuWithTheSameLabel('First'); // Check if backButtonMenu works | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
}); | ||
}); | ||
|
||
describe('backButtonDisplayMode: generic', () => { | ||
it('with default text', async () => { | ||
await element(by.text('EnabledGenericDefaultText')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.text('Back'))).toBeVisible(); | ||
await expectBackButtonMenuWithDifferentLabels('Back', 'First'); // Check if backButtonMenu works | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
}); | ||
|
||
// TODO: We should be able to fix that | ||
// Custom text overrides backButtonDisplayMode | ||
it('has custom text', async () => { | ||
await element(by.text('EnabledGenericCustomText')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.text('Custom'))).toBeVisible(); // TODO: We should be able to fix that | ||
await expectBackButtonMenuWithTheSameLabel('Custom'); // Check if backButtonMenu works | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
}); | ||
|
||
// Custom styles override backButtonDisplayMode | ||
it('with custom text', async () => { | ||
await element(by.text('EnabledGenericStyledText')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.text('First'))).toBeVisible(); | ||
await expectBackButtonMenuWithTheSameLabel('First'); // Check if backButtonMenu works | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
}); | ||
}); | ||
|
||
describe('backButtonDisplayMode: minimal', () => { | ||
it('with default text', async () => { | ||
await element(by.text('EnabledMinimalDefaultText')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.id('chevron.backward'))).toBeVisible(); | ||
await expect(element(by.text('First'))).not.toBeVisible(); | ||
await expectBackButtonMenuIconAndLabel('chevron.backward', 'First'); // Check if backButtonMenu works | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
}); | ||
|
||
it('with custom text', async () => { | ||
await element(by.text('EnabledMinimalCustomText')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.id('chevron.backward'))).toBeVisible(); | ||
await expect(element(by.text('Custom'))).not.toBeVisible(); | ||
await expectBackButtonMenuIconAndLabel('chevron.backward', 'Custom'); // Check if backButtonMenu works | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
}); | ||
|
||
it('with styled text', async () => { | ||
await element(by.text('EnabledMinimalStyledText')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.id('chevron.backward'))).toBeVisible(); | ||
await expect(element(by.text('First'))).not.toBeVisible(); | ||
await expectBackButtonMenuIconAndLabel('chevron.backward', 'First'); // Check if backButtonMenu works | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
}); | ||
}); | ||
}); | ||
|
||
describe('backButtonMenuEnabled: false', () => { | ||
describe('backButtonDisplayMode: default', () => { | ||
it('with default text', async () => { | ||
await element(by.text('DisabledDefaultDefaultText')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.text('First'))).toBeVisible(); | ||
await expectBackButtonMenuToNotExistOnLabel('First'); // Check if backButtonMenu is disabled | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
}); | ||
|
||
it('with custom text', async () => { | ||
await element(by.text('DisabledDefaultCustomText')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.text('Custom'))).toBeVisible(); | ||
await expectBackButtonMenuToNotExistOnLabel('Custom'); // Check if backButtonMenu is disabled | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this can be refactored out to a function with some parameters, right? We do not need to repeat it every single time. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. changed in: d1c0127 |
||
}); | ||
|
||
it('with styled text', async () => { | ||
await element(by.text('DisabledDefaultStyledText')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.text('First'))).toBeVisible(); | ||
await expectBackButtonMenuToNotExistOnLabel('First'); // Check if backButtonMenu is disabled | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
}); | ||
}); | ||
|
||
// [backButtonMenuEnabled: false and backButtonDisplayMode: generic] | ||
// generic is not working as currently backButtonDisplayMode is causing backButtonItem to be set | ||
describe('backButtonDisplayMode: generic not working', () => { | ||
it('with default text', async () => { | ||
await element(by.text('DisabledGenericDefaultText')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.text('First'))).toBeVisible(); | ||
await expectBackButtonMenuToNotExistOnLabel('First'); // Check if backButtonMenu is disabled | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
}); | ||
|
||
it('with custom text', async () => { | ||
await element(by.text('DisabledGenericCustomText')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.text('Custom'))).toBeVisible(); | ||
await expectBackButtonMenuToNotExistOnLabel('Custom'); // Check if backButtonMenu is disabled | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
}); | ||
|
||
it('with styled text', async () => { | ||
await element(by.text('DisabledGenericStyledText')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.text('First'))).toBeVisible(); | ||
await expectBackButtonMenuToNotExistOnLabel('First'); // Check if backButtonMenu is disabled | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
}); | ||
}); | ||
|
||
// [backButtonMenuEnabled: false and backButtonDisplayMode: minimal] | ||
// backButtonDisplayMode: minimal works as a kill switch so backButtonMenu value is omitted | ||
describe('backButtonDisplayMode: minimal', () => { | ||
it('with default text', async () => { | ||
await element(by.text('DisabledMinimalDefaultText')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.id('chevron.backward'))).toBeVisible(); | ||
await expect(element(by.text('First'))).not.toBeVisible(); | ||
await expectBackButtonMenuIconAndLabel('chevron.backward', 'First'); // Check if backButtonMenu works | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
}); | ||
|
||
it('with custom text', async () => { | ||
await element(by.text('DisabledMinimalCustomText')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.id('chevron.backward'))).toBeVisible(); | ||
await expect(element(by.text('Custom'))).not.toBeVisible(); | ||
await expectBackButtonMenuIconAndLabel('chevron.backward', 'Custom'); // Check if backButtonMenu works | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
}); | ||
|
||
it('with styled text', async () => { | ||
await element(by.text('DisabledMinimalStyledText')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.id('chevron.backward'))).toBeVisible(); | ||
await expect(element(by.text('First'))).not.toBeVisible(); | ||
await expectBackButtonMenuIconAndLabel('chevron.backward', 'First'); // Check if backButtonMenu works | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
}); | ||
}); | ||
}); | ||
|
||
// Custom | ||
it('Default long back label should be truncated to generic by buckButtonDisplayMode', async () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These titles are very nice |
||
await element(by.text('CustomLongDefaultText')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.text('Back'))).toBeVisible(); | ||
await expectBackButtonMenuWithDifferentLabels('Back', 'LongLongLongLongLong'); // Check if backButtonMenu works | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
}); | ||
|
||
it('Default label should be truncated to minimal by buckButtonDisplayMode when title is long', async () => { | ||
await element(by.text('CustomDefaultTextWithLongTitle')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.id('chevron.backward'))).toBeVisible(); | ||
await expect(element(by.text('First'))).not.toBeVisible(); | ||
await expectBackButtonMenuIconAndLabel('chevron.backward', 'First'); // Check if backButtonMenu works | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
}); | ||
|
||
// TODO: We should be able to fix that | ||
// Custom text overrides backButtonDisplayMode because of using backButtonItem | ||
it.failing('Custom long back label should be truncated to generic by buckButtonDisplayMode', async () => { | ||
await element(by.text('CustomLongCustomText')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.text('Back'))).toBeVisible(); | ||
await expectBackButtonMenuWithDifferentLabels('Back', 'LongLongLongLongLong'); // Check if backButtonMenu works | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
}); | ||
|
||
// TODO: We should be able to fix that | ||
// Custom text overrides backButtonDisplayMode because of using backButtonItem | ||
it.failing('Custom back label should be truncated to minimal by buckButtonDisplayMode when title is long', async () => { | ||
await element(by.text('CustomCustomTextWithLongTitle')).tap(); | ||
await element(by.text('Open screen')).tap(); | ||
await expect(element(by.id('chevron.backward'))).toBeVisible(); | ||
await expect(element(by.text('CustomBack'))).not.toBeVisible(); | ||
await expectBackButtonMenuIconAndLabel('chevron.backward', 'CustomBack'); // Check if backButtonMenu works | ||
await element(by.text('Pop to top')).tap(); // Go back | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import * as React from 'react'; | ||
import { Button, Text, View } from 'react-native'; | ||
import { ParamListBase } from '@react-navigation/native'; | ||
import { | ||
createNativeStackNavigator, | ||
NativeStackNavigationOptions, | ||
NativeStackNavigationProp, | ||
} from '@react-navigation/native-stack'; | ||
|
||
|
||
export function FinalScreen({ | ||
navigation, | ||
}: { | ||
navigation: NativeStackNavigationProp<ParamListBase>; | ||
}) { | ||
return ( | ||
<View style={{ flex: 1, backgroundColor: 'yellow', justifyContent: 'center', alignItems: 'center' }}> | ||
<Text>VOID</Text> | ||
<Button title="Pop to top" onPress={() => navigation.popTo('Home')} /> | ||
</View> | ||
); | ||
} | ||
|
||
export function Home({ | ||
navigation, | ||
}: { | ||
navigation: NativeStackNavigationProp<ParamListBase>; | ||
}) { | ||
return ( | ||
<View style={{ flex: 1, backgroundColor: 'yellow' }}> | ||
<Button | ||
title="Open screen" | ||
onPress={() => navigation.navigate('Second')} | ||
/> | ||
</View> | ||
); | ||
} | ||
|
||
export const createStackWithOptions = (options1: NativeStackNavigationOptions, options2: NativeStackNavigationOptions) => () => { | ||
const Stack = createNativeStackNavigator(); | ||
|
||
return ( | ||
<Stack.Navigator> | ||
<Stack.Screen name="First" component={Home} options={options1} /> | ||
<Stack.Screen name="Second" component={FinalScreen} options={options2} /> | ||
</Stack.Navigator> | ||
); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just one note to all the tests - would be nice if the string in
it
better described our expectations regarding the test, so that it is more readable from terminal what the test does. I'm not claiming that my suggestion is even good, but would be nice to come up with something more readable.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed in: d1c0127