Как правильно тестировать React Native Modals с помощью Jest и Native Testing Library
Мне сложно понять, как тестировать мой модальный компонент. Я использую пакет response-native-modals и @testing-library/react-native с Jest. Мой компонент - это модальное окно, которое появляется, когда ему передается ошибка GraphQL.
./ErrorMessage.js
import React from 'react';
import PropTypes from 'prop-types';
import { Dimensions, Text } from 'react-native';
import Modal, { ModalContent, ScaleAnimation } from 'react-native-modals';
import { theme } from '../styles/theme.styles';
const ModalError = ({ error, onClose }) => {
if (!error || !error.message) {
return (
<Modal visible={false}>
<Text />
</Modal>
);
}
return (
<Modal
visible
modalAnimation={
new ScaleAnimation({
initialValue: 0,
useNativeDriver: true,
})
}
onTouchOutside={onClose}
swipeDirection={['up', 'down', 'left', 'right']}
swipeThreshold={200}
onSwipeOut={onClose}
modalStyle={modalStyle}
overlayOpacity={0.7}
>
<ModalContent>
<Text testID="graphql-error">{error.message}</Text>
</ModalContent>
</Modal>
);
};
ModalError.defaultProps = {
error: {},
};
ModalError.propTypes = {
error: PropTypes.object,
onClose: PropTypes.func.isRequired,
};
export default ModalError;
const window = Dimensions.get('window');
const modalStyle = {
backgroundColor: theme.lightRed,
borderLeftWidth: 5,
borderLeftColor: theme.red,
width: window.width / 1.12,
};
Пока что мой тест довольно прост. Я просто хочу убедиться, что он отображает модальное окно. Я не совсем уверен, что здесь нужно высмеивать и как это делать.
./__tests__/ErrorMessage.test.js
import React from 'react';
import { MockedProvider } from '@apollo/react-testing';
import { GraphQLError } from 'graphql';
import { render } from '@testing-library/react-native';
import Error from '../ErrorMessage';
jest.mock('react-native-modals', () => 'react-native-modals');
const error = new GraphQLError('This is a test error message.');
const handleOnCloseError = jest.fn();
describe('<ErrorMessage>', () => {
it('should render an ErrorMessage modal component', () => {
const { container } = render(
<MockedProvider>
<Error error={error} onClose={handleOnCloseError} />
</MockedProvider>
);
expect(container).toMatchSnapshot();
});
});
Ошибка, которую я получаю...
TypeError: _reactNativeModals.ScaleAnimation is not a constructor
18 | visible
19 | modalAnimation={
> 20 | new ScaleAnimation({
| ^
21 | initialValue: 0,
22 | useNativeDriver: true,
23 | })
А снимок только распечатывается...
./__tests__/__snapshots__/ErrorMessage.test.js.snap
// Jest Snapshot v1,
exports[`<ErrorMessage> should render an ErrorMessage modal component 1`] = `
<View
collapsable={true}
pointerEvents="box-none"
style={
Object {
"flex": 1,
}
}
/>
`;
Как я могу обойти эту ошибку и сделать правильный снимок?
3 ответа
// components/Example/index.tsx
import React, { useState } from 'react';
import { Pressable, Text } from 'react-native';
import Modal from 'react-native-modal';
const Example: React.FC = () => {
const [isPrivacyPolicyVisible, setIsPrivacyPolicyVisible] = useState(false);
return (
<>
<Pressable onPress={() => setIsPrivacyPolicyVisible(true)}>
<Text>Privacy Policy</Text>
</Pressable>
<Modal
accessibilityLabel="privacy-policy-modal"
isVisible={isPrivacyPolicyVisible}>
<Text>Content</Text>
</Modal>
</>
);
};
export default Example;
// components/Example/index.test.tsx
import React from 'react';
import { fireEvent, render, waitFor } from '@testing-library/react-native';
import { Example } from 'components';
describe('Example Component', () => {
it('should render privacy policy.', async () => {
// Arrange
const { queryByText, queryByA11yLabel } = render(<Example />);
const button = queryByText(/privacy policy/i);
const modal = queryByA11yLabel('privacy-policy-modal');
// Act and Assert
expect(button).toBeTruthy();
expect(modal).toBeTruthy();
expect(modal.props).toMatchObject({
visible: false,
});
});
it('should show privacy policy modal.', async () => {
// Arrange
const { queryByText, queryByA11yLabel } = render(<Example />);
const button = queryByText(/privacy policy/i);
const modal = queryByA11yLabel('privacy-policy-modal');
// Act
await waitFor(() => {
fireEvent.press(button);
});
// Assert
expect(modal.props).toMatchObject({
visible: true,
});
});
});
вы можете использовать это → https://github.com/testing-library/jest-native
In react native component,
...
<Modal
testID="test-modal"
deviceWidth={deviceWidth}
deviceHeight={deviceHeight}
isVisible={isModalVisible}. // isModalVisible = useState(true or false)
onBackdropPress={toggleModal}
backdropOpacity={0.5}
>
...
In test component,
...
const test = getByTestId("test-modal");
expect(test).toHaveProp("visible", true); // test success !
...
Когда ты делаешь
jest.mock('react-native-modals', () => 'react-native-modals');
вы заменяете всю библиотеку на строку "react-native-modals", поэтому, когда вы используете ее в своем компоненте, она не работает. Вам нужно вернуть полную фиктивную реализацию из своей фиктивной функции (второй аргумент jest.mock). Также возможно, что у вас может сработать автоматическое издевательство, которое можно сделать, просто выполнив:
jest.mock('react-native-modals');
Вот доки для jest.mock() с некоторыми примерами различных способов его использования: https://jestjs.io/docs/en/jest-object#jestmockmodulename-factory-options.