* Copyright (c) 2025 Huawei Technologies Co., Ltd.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {TestSuite} from '@rnoh/testerino';
import React, {useEffect, useState} from 'react';
import {GestureResponderEvent, ScrollView, TextInput} from 'react-native';
import {
AppState,
AppStateStatus,
StyleProp,
StyleSheet,
Text,
View,
ViewStyle,
} from 'react-native';
import {Button, Effect, TestCase} from '../components';
export function AppStateTest() {
return (
<TestSuite name="AppState">
<TestCase.Logical
itShould="return active"
fn={({expect}) => {
expect(AppState.currentState).to.equal('active');
}}
/>
<TestCase.Example itShould="show AppState history">
<AppStateHistoryView />
</TestCase.Example>
<TestCase.Example
skip={{android: false, harmony: {arkTs: true, cAPI: true}}}
itShould="show focus history">
<FocusHistoryView />
</TestCase.Example>
<TestCase.Manual
skip={{android: false, harmony: {arkTs: false, cAPI: false}}}
itShould="throw memory warning event after adding too much items"
initialState={{
didEmitMemoryEvent: false,
childrenCount: 1,
textInputValue: '99',
}}
arrange={({setState, state}) => {
return (
<View>
<Effect
onMount={() => {
AppState.addEventListener('memoryWarning', () => {
setState(prev => ({...prev, didEmitMemoryEvent: true}));
});
}}
children={<></>}
/>
<View style={{flexDirection: 'row'}}>
<Text>Number of items to add</Text>
<TextInput
value={state.textInputValue}
onChange={e => {
e.persist();
setState(prev => ({
...prev,
textInputValue: e.nativeEvent?.text,
}));
}}
style={{borderWidth: 1, width: 50, marginLeft: 10}}
maxLength={6}
/>
</View>
<Text>Items: {state.childrenCount}</Text>
<Button
onPress={() => {
setState(prev => ({
...prev,
childrenCount:
prev.childrenCount + parseInt(state.textInputValue, 10),
}));
}}
label="Add"
/>
<ScrollView
{...COMMON_PROPS}
nestedScrollEnabled
children={getScrollViewContent({
amountOfChildren: state.childrenCount,
})}
style={{
height: 100,
}}
/>
</View>
);
}}
assert={({expect, state}) => {
expect(state).to.be.true;
}}
/>
</TestSuite>
);
}
const FocusHistoryView = () => {
const [focusHistory, setFocusHistory] = useState('focused');
useEffect(() => {
const handleFocusChange = (focusState: 'blurred' | 'focused') => () => {
setFocusHistory((prev: string) => `${prev}, ${focusState}`);
};
AppState.addEventListener('blur', handleFocusChange('blurred'));
AppState.addEventListener('focus', handleFocusChange('focused'));
}, []);
return (
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}}>
<Text style={styles.text}>Focus history: {focusHistory}</Text>
</View>
);
};
const COMMON_PROPS = {
style: {
borderWidth: 3,
borderColor: 'firebrick',
},
contentContainerStyle: {
alignItems: 'center' as 'center',
justifyContent: 'center' as 'center',
},
children: getScrollViewContent({}),
};
interface ScrollViewContentProps {
style?: StyleProp<ViewStyle>;
amountOfChildren?: number;
onTouchEnd?: (event: GestureResponderEvent) => void;
pointerEvents?: 'box-none' | 'none' | 'box-only' | 'auto' | undefined;
}
function getScrollViewContent({
style,
amountOfChildren = 20,
onTouchEnd,
pointerEvents,
}: ScrollViewContentProps) {
return new Array(amountOfChildren).fill(0).map((_, idx) => {
return (
<View
key={idx}
style={[
{
width: '100%',
height: 50,
backgroundColor: idx % 2 ? 'pink' : 'beige',
justifyContent: 'center',
},
style,
]}
pointerEvents={pointerEvents}
onTouchEnd={onTouchEnd}>
<Text style={{textAlign: 'center', height: 15}}> {idx + 1}</Text>
</View>
);
});
}
const AppStateHistoryView = () => {
const [appState, setAppState] = useState(AppState.currentState);
const [appStateHistory, setAppStateHistory] = useState(
AppState.currentState.toString(),
);
useEffect(() => {
const handleAppStateChange = (nextAppState: AppStateStatus) => {
setAppState(nextAppState);
setAppStateHistory(
(prevAppStateHistory: string) =>
prevAppStateHistory + ', ' + nextAppState,
);
};
AppState.addEventListener('change', handleAppStateChange);
}, []);
return (
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}}>
<Text style={styles.text}>Current AppState: {appState}</Text>
<Text style={styles.text}>AppState history: {appStateHistory}</Text>
</View>
);
};
const styles = StyleSheet.create({
text: {
marginBottom: 10,
fontSize: 14,
},
});