Skip to content

Commit 16e6ae9

Browse files
authored
test(e2e, Fabric): add e2e test for issue/PR example 593 (#2849)
## Description Create e2e test for `Test593`. ### Test 593 Test created. Test screen changed to allow using `default` and `none` stack animations. Events and their order is different than in related PRs (#593, #941) but it matches behavior from `Events` test screen. ## Changes - add e2e test for `Test593` - add comment in `apps/src/tests/index.ts` ## Test code and steps to reproduce CI ## Checklist - [x] Ensured that CI passes
1 parent a6fd3d9 commit 16e6ae9

3 files changed

Lines changed: 204 additions & 10 deletions

File tree

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import { device, expect, element, by } from 'detox';
2+
3+
const awaitValidEventBehavior = async () => {
4+
await expect(
5+
element(by.text('3. Status | transitionStart | closing')),
6+
).toExist();
7+
await expect(
8+
element(by.text('4. Deeper | transitionStart | opening')),
9+
).toExist();
10+
await expect(
11+
element(by.text('5. Privacy | transitionStart | opening')),
12+
).toExist();
13+
await expect(
14+
element(by.text('6. Status | transitionEnd | closing')),
15+
).toExist();
16+
await expect(
17+
element(by.text('7. Deeper | transitionEnd | opening')),
18+
).toExist();
19+
await expect(
20+
element(by.text('8. Privacy | transitionEnd | opening')),
21+
).toExist();
22+
await expect(
23+
element(by.text('9. Privacy | transitionStart | closing')),
24+
).toExist();
25+
await expect(
26+
element(by.text('10. Another | transitionStart | opening')),
27+
).toExist();
28+
await expect(
29+
element(by.text('11. Privacy | transitionEnd | closing')),
30+
).toExist();
31+
await expect(
32+
element(by.text('12. Another | transitionEnd | opening')),
33+
).toExist();
34+
if (device.getPlatform() === 'ios') {
35+
await expect(
36+
element(by.text('13. Deeper | transitionStart | closing')),
37+
).toExist();
38+
await expect(
39+
element(by.text('14. Another | transitionStart | closing')),
40+
).toExist();
41+
await expect(
42+
element(by.text('15. Status | transitionStart | opening')),
43+
).toExist();
44+
await expect(
45+
element(by.text('16. Deeper | transitionEnd | closing')),
46+
).toExist();
47+
await expect(
48+
element(by.text('17. Another | transitionEnd | closing')),
49+
).toExist();
50+
await expect(
51+
element(by.text('18. Status | transitionEnd | opening')),
52+
).toExist();
53+
} else {
54+
await expect(
55+
element(by.text('13. Status | transitionStart | opening')),
56+
).toExist();
57+
await expect(
58+
element(by.text('14. Status | transitionEnd | opening')),
59+
).toExist();
60+
}
61+
};
62+
63+
describe('Test593', () => {
64+
beforeEach(async () => {
65+
await device.reloadReactNative();
66+
67+
await waitFor(element(by.id('root-screen-tests-Test593')))
68+
.toBeVisible()
69+
.whileElement(by.id('root-screen-examples-scrollview'))
70+
.scroll(600, 'down', NaN, 0.85);
71+
});
72+
73+
it('Test593 should exist', async () => {
74+
await expect(element(by.id('root-screen-tests-Test593'))).toBeVisible();
75+
await element(by.id('root-screen-tests-Test593')).tap();
76+
});
77+
78+
it('should run transitionStart & transitionEnd opening events', async () => {
79+
await element(by.id('root-screen-tests-Test593')).tap();
80+
81+
await expect(
82+
element(by.text('1. Status | transitionStart | opening')),
83+
).toExist();
84+
await expect(
85+
element(by.text('2. Status | transitionEnd | opening')),
86+
).toExist();
87+
});
88+
89+
it('should go back from screen in nested stack and run opening & closing events in correct order', async () => {
90+
await element(by.id('root-screen-tests-Test593')).tap();
91+
92+
await element(by.id('status-button-go-to-deeper')).tap();
93+
await element(by.id('privacy-button-go-to-another')).tap();
94+
95+
if (device.getPlatform() === 'ios') {
96+
await element(by.type('_UIButtonBarButton')).atIndex(0).tap();
97+
} else {
98+
await element(by.type('androidx.appcompat.widget.AppCompatImageButton'))
99+
.atIndex(0)
100+
.tap();
101+
}
102+
103+
await awaitValidEventBehavior();
104+
});
105+
106+
it('should use "none" animation, go back from screen in nested stack and run opening & closing events in correct order', async () => {
107+
await element(by.id('root-screen-tests-Test593')).tap();
108+
109+
await element(by.id('Test593-stack-animation-picker')).tap();
110+
await element(by.id('stack-animation-none')).tap();
111+
112+
await element(by.id('status-button-go-to-deeper')).tap();
113+
await element(by.id('privacy-button-go-to-another')).tap();
114+
115+
if (device.getPlatform() === 'ios') {
116+
await element(by.type('_UIButtonBarButton')).atIndex(0).tap();
117+
} else {
118+
await element(by.type('androidx.appcompat.widget.AppCompatImageButton'))
119+
.atIndex(0)
120+
.tap();
121+
}
122+
123+
await awaitValidEventBehavior();
124+
});
125+
});

apps/src/tests/Test593.tsx

Lines changed: 78 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
/* eslint-disable react-hooks/exhaustive-deps */
2-
import React, { createContext, useState, useContext, useEffect } from 'react';
2+
import React, {
3+
createContext,
4+
useState,
5+
useContext,
6+
useEffect,
7+
useLayoutEffect,
8+
} from 'react';
39
import {
410
ScrollView,
511
Button,
@@ -15,19 +21,38 @@ import { nanoid } from 'nanoid/non-secure';
1521
import { NavigationContainer, ParamListBase } from '@react-navigation/native';
1622
import {
1723
createNativeStackNavigator,
24+
NativeStackNavigationOptions,
1825
NativeStackNavigationProp,
1926
} from '@react-navigation/native-stack';
27+
import { SettingsPicker } from '../shared';
2028

2129
type Props = {
2230
navigation: NativeStackNavigationProp<ParamListBase>;
2331
};
2432

33+
type NavigatorProps = {
34+
navigation: NativeStackNavigationProp<ParamListBase>;
35+
stackAnimation: StackAnimation;
36+
setStackAnimation: (value: StackAnimation) => void;
37+
};
38+
39+
type StackAnimation = Exclude<
40+
NativeStackNavigationOptions['animation'],
41+
undefined
42+
>;
43+
2544
const Stack = createNativeStackNavigator();
2645
const NestedStack = createNativeStackNavigator();
2746

28-
function Deeper({ navigation }: Props) {
47+
function Deeper({ navigation, stackAnimation }: NavigatorProps) {
2948
const toast = useToast();
3049

50+
useLayoutEffect(() => {
51+
navigation.setOptions({
52+
animation: stackAnimation,
53+
});
54+
}, [navigation, stackAnimation]);
55+
3156
useEffect(() => {
3257
const unsubscribe = navigation.addListener(
3358
'transitionStart',
@@ -88,7 +113,7 @@ function Deeper({ navigation }: Props) {
88113
<NestedStack.Navigator
89114
screenOptions={{
90115
headerShown: true,
91-
animation: 'slide_from_right',
116+
animation: stackAnimation,
92117
}}>
93118
<NestedStack.Screen name="Privacy" component={Privacy} />
94119
<NestedStack.Screen name="Another" component={Another} />
@@ -97,24 +122,53 @@ function Deeper({ navigation }: Props) {
97122
}
98123

99124
export default function NativeNavigation() {
125+
const [stackAnimation, setStackAnimation] =
126+
useState<StackAnimation>('default');
127+
100128
return (
101129
<NavigationContainer>
102130
<ToastProvider>
103131
<Stack.Navigator
104132
screenOptions={{
105-
animation: 'slide_from_bottom',
133+
animation: stackAnimation,
106134
}}>
107-
<Stack.Screen name="Status" component={Status} />
108-
<Stack.Screen name="Deeper" component={Deeper} />
135+
<Stack.Screen name="Status">
136+
{({ navigation }) => (
137+
<Status
138+
navigation={navigation}
139+
stackAnimation={stackAnimation}
140+
setStackAnimation={setStackAnimation}
141+
/>
142+
)}
143+
</Stack.Screen>
144+
<Stack.Screen name="Deeper">
145+
{({ navigation }) => (
146+
<Deeper
147+
navigation={navigation}
148+
stackAnimation={stackAnimation}
149+
setStackAnimation={setStackAnimation}
150+
/>
151+
)}
152+
</Stack.Screen>
109153
</Stack.Navigator>
110154
</ToastProvider>
111155
</NavigationContainer>
112156
);
113157
}
114158

115-
function Status({ navigation }: Props) {
159+
function Status({
160+
navigation,
161+
stackAnimation,
162+
setStackAnimation,
163+
}: NavigatorProps) {
116164
const toast = useToast();
117165

166+
useLayoutEffect(() => {
167+
navigation.setOptions({
168+
animation: stackAnimation,
169+
});
170+
}, [navigation, stackAnimation]);
171+
118172
useEffect(() => {
119173
const unsubscribe = navigation.addListener(
120174
'transitionStart',
@@ -173,7 +227,18 @@ function Status({ navigation }: Props) {
173227

174228
return (
175229
<ScrollView>
176-
<Button title="Click" onPress={() => navigation.navigate('Deeper')} />
230+
<SettingsPicker<StackAnimation>
231+
testID="Test593-stack-animation-picker"
232+
label="Stack animation"
233+
value={stackAnimation}
234+
onValueChange={setStackAnimation}
235+
items={['default', 'none']}
236+
/>
237+
<Button
238+
title="Click"
239+
onPress={() => navigation.navigate('Deeper')}
240+
testID="status-button-go-to-deeper"
241+
/>
177242
</ScrollView>
178243
);
179244
}
@@ -239,7 +304,11 @@ function Privacy({ navigation }: Props) {
239304

240305
return (
241306
<View style={{ flex: 1, backgroundColor: 'rgba(255,0,0,0.2)' }}>
242-
<Button title="Click" onPress={() => navigation.navigate('Another')} />
307+
<Button
308+
title="Click"
309+
onPress={() => navigation.navigate('Another')}
310+
testID="privacy-button-go-to-another"
311+
/>
243312
</View>
244313
);
245314
}

apps/src/tests/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export { default as Test550 } from './Test550'; // [E2E skipped]: the prop d
1111
export { default as Test556 } from './Test556'; // [E2E skipped]: can't check flickering nor non-deterministic white screen bug
1212
export { default as Test564 } from './Test564'; // [E2E skipped]: issue still present
1313
export { default as Test577 } from './Test577'; // [E2E created](iOS): issue is related to iOS modal
14-
export { default as Test593 } from './Test593';
14+
export { default as Test593 } from './Test593'; // [E2E created]
1515
export { default as Test619 } from './Test619';
1616
export { default as Test624 } from './Test624';
1717
export { default as Test640 } from './Test640';

0 commit comments

Comments
 (0)