I’m writing testing code for the component, but I don’t know where to ask, so I’m asking a question.
I am using @testing-libray/react-native and jest.
When the background is pressed for the first rendering.
I wrote test code for when the photo button was pressed and when the camera button was pressed.
I am asking a question using one specific component as an example because I am unable to verify whether it is possible to write it like the code above or whether there is an incorrect way of writing it.
Is it correct to write it like the code below? Or is there a better direction?
import { View, StyleSheet, Text, TouchableOpacity } from 'react-native';
import Modal from 'react-native-modal';
import * as ImagePicker from 'expo-image-picker';
type ImagePickerComponentProps = {
visible: boolean;
onCancel: () => void;
setImage: (image: string) => void;
};
const ImagePickerComponent = ({ visible, onCancel, setImage }: ImagePickerComponentProps) => {
const { t } = useTranslation();
const pickImage = async () => {
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: false,
quality: 1,
});
if (!result.canceled && result.assets && result.assets.length > 0) {
setImage(result.assets[0].uri);
onCancel();
}
};
const takePhoto = async () => {
const result = await ImagePicker.launchCameraAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: false,
quality: 1,
});
if (!result.canceled && result.assets && result.assets.length > 0) {
setImage(result.assets[0].uri);
onCancel();
}
};
return (
<Modal
testID="image-picker-modal"
isVisible={visible}
onBackdropPress={onCancel}
onBackButtonPress={onCancel}
style={{ justifyContent: 'flex-end', margin: 0 }}
backdropTransitionOutTiming={0}
backdropTransitionInTiming={0}
customBackdrop={<TouchableOpacity testID="backdrop" onPress={onCancel} style={{ flex: 1, backgroundColor: 'rgba(0, 0, 0, 0.5)' }} />}
>
<View testID="image-picker-modal-content" style={styles.modalContent}>
<TouchableOpacity testID="photo-button" onPress={pickImage} style={styles.modalButton}>
<View
style={[
styles.modalImage,
{
backgroundColor: lightTheme.skyBlue,
},
]}
>
<Entypo name="image" size={scale(20)} color="white" />
</View>
<Text style={styles.modalText}>{t('account.photo')}</Text>
</TouchableOpacity>
<TouchableOpacity testID="camera-button" onPress={takePhoto} style={styles.modalButton}>
<View
style={[
styles.modalImage,
{
backgroundColor: lightTheme.emerald,
},
]}
>
<Entypo name="camera" size={scale(20)} color="white" />
</View>
<Text style={styles.modalText}>{t('account.camera')}</Text>
</TouchableOpacity>
</View>
</Modal>
);
};
export default ImagePickerComponent;
import React from 'react';
import * as ImagePicker from 'expo-image-picker';
import { fireEvent, render, waitFor } from '@testing-library/react-native';
import ImagePickerComponent from '../ImagePickerComponent';
describe('ImagePickerComponent', () => {
const onCancel = jest.fn();
const setImage = jest.fn();
beforeEach(() => {
jest.clearAllMocks();
});
it('visible이 true일 때 올바르게 렌더링된다', () => {
const { getByTestId } = render(<ImagePickerComponent visible onCancel={onCancel} setImage={setImage} />);
expect(getByTestId('image-picker-modal')).toBeTruthy();
expect(getByTestId('photo-button')).toBeTruthy();
expect(getByTestId('camera-button')).toBeTruthy();
});
it('백드롭을 눌렀을 때 onCancel이 호출된다', async () => {
const { getByTestId, rerender } = render(<ImagePickerComponent visible onCancel={onCancel} setImage={setImage} />);
fireEvent.press(getByTestId('backdrop'));
await waitFor(() => {
expect(onCancel).toHaveBeenCalled();
});
await waitFor(
() => {
rerender(<ImagePickerComponent visible={false} onCancel={onCancel} setImage={setImage} />);
expect(getByTestId('image-picker-modal')).toBeVisible();
},
);
});
it('사진 버튼을 눌렀을 때 사진 선택 모달이 나타나고 사진이 선택되면 setImage가 호출된다', async () => {
jest.spyOn(ImagePicker, 'launchImageLibraryAsync').mockResolvedValue({
canceled: false,
assets: [{ uri: 'test-uri', width: 100, height: 100 }],
});
const { getByTestId } = render(<ImagePickerComponent visible onCancel={onCancel} setImage={setImage} />);
await waitFor(async () => {
fireEvent.press(getByTestId('photo-button'));
});
await waitFor(() => {
expect(ImagePicker.launchImageLibraryAsync).toHaveBeenCalledWith({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: false,
quality: 1,
});
expect(setImage).toHaveBeenCalledWith('test-uri');
expect(onCancel).toHaveBeenCalled();
});
});
it('카메라 버튼을 눌렀을 때 카메라 모달이 나타나고 사진이 촬영되면 setImage가 호출된다', async () => {
jest.spyOn(ImagePicker, 'launchCameraAsync').mockResolvedValue({
canceled: false,
assets: [{ uri: 'test-uri', width: 100, height: 100 }],
});
const { getByTestId } = render(<ImagePickerComponent visible onCancel={onCancel} setImage={setImage} />);
await waitFor(async () => {
fireEvent.press(getByTestId('camera-button'));
});
await waitFor(() => {
expect(ImagePicker.launchCameraAsync).toHaveBeenCalled();
expect(setImage).toHaveBeenCalledWith('test-uri');
expect(onCancel).toHaveBeenCalled();
});
});
});