В предыдущем уроке я обсуждал неглубокий или монтируемый в Enzyme. В этом руководстве мы подробнее рассмотрим тестирование с помощью Jest и Enzyme, написав тесты для рендеринга, взаимодействий и вызовов методов жизненного цикла.
Во-первых, у вас должен быть проект под названием «testing-demo-app», который я использовал в предыдущих руководствах. Вы можете найти его по ссылке ниже.
wasuradananjith / testing-demo-app
Это исходный код для серии руководств« Тестирование с помощью Jest и Enzyme в React … github.com»
Давайте напишем несколько тестов для рендеринга, взаимодействий и l вызовов методов ifecycle.
Шаг 1 - Написание тестов для рендеринга
- Сначала создайте новый файл с именем Form.test .js в папке testing-demo-app / test со следующим содержимым.
import Form from '../src/components/Form'; let wrapper; beforeEach(() => { wrapper = shallow(<Form/>); }); describe('<Form /> rendering', () => { it('should render one <form>', () => { expect(wrapper.find('form')).toHaveLength(1); }); it('should not render any <button> when operator is not passed in props', () => { expect(wrapper.find('button')).toHaveLength(0); }); it('should render 2 <label>s', () => { expect(wrapper.find('label')).toHaveLength(2); }); it('should render 2 <input>s', () => { expect(wrapper.find('input')).toHaveLength(2); }); });
- Откройте терминал в каталоге проекта и выполните приведенную ниже команду, чтобы запустить тесты в файле Form.test.js.
npm test Form.test.js
- Тесты должны пройти следующим образом.
- Первый тест проверяет, есть ли один элемент ‹form› при отображении ‹Form›.
- Второй тест особенный. Если вы проверите файл Form.js в testing-demo-app / src / components, вы увидите, что если оператор не передан, будет отображена кнопка. В этом тесте мы это проверяем. Мы не передаем оператор как опору при инициализации оболочки. Из-за этого никакая кнопка не будет отображаться.
- Третий тест проверяет наличие 2 ‹label› с. (Они должны пометить ПЕРВЫЙ НОМЕР и ВТОРОЙ НОМЕР в пользовательском интерфейсе)
- Четвертый тест проверяет, есть ли 2 ‹inputs›, в которые нужно ввести добавляемые числа.
- Давайте добавим еще 2 теста следующим образом и запустим его снова.
it('should render one <button> to Add when operator \'+\' is passed in props', () => { wrapper.setProps({ operator: '+' } ); expect(wrapper.find('#formButtonAdd')).toHaveLength(1); expect(wrapper.find('#formButtonSubtract')).toHaveLength(0); }); it('should render one <button> to Subtract when operator \'-\' is passed in props', () => { wrapper.setProps({ operator: '-' } ); expect(wrapper.find('#formButtonAdd')).toHaveLength(0); expect(wrapper.find('#formButtonSubtract')).toHaveLength(1); });
- В недавно добавленном пятом тесте мы установили для оператора свойства «+». Согласно тому, что мы обсуждали во время второго теста, теперь ‹Form› должен иметь ‹button›. Здесь мы ищем эту ‹button›, используя ее идентификатор «formButtonAdd».
- Точно так же в шестом тесте мы устанавливаем для оператора свойства "-" и проверяем, существует ли ‹button› с идентификатором formButtonSubtract. '.
Шаг 2 - Написание тестов для взаимодействий
- Добавьте еще один набор тестов в «‹Form› взаимодействий» в Form.test.js, как показано ниже, и снова запустите файл.
describe('<Form /> interactions', () => { it('should change the state firstNumber when onChange function of the #number1 input is invoked', () => { wrapper.find('#number1').simulate('change', { target: { value: 50 } } ); expect(wrapper.state('firstNumber')).toEqual(50); expect(wrapper.state('secondNumber')).toEqual(''); }); it('should change the state secondNumber when onChange function of the #number2 input is invoked', () => { wrapper.find('#number2').simulate('change', { target: { value: 60 } } ); expect(wrapper.state('secondNumber')).toEqual(60); expect(wrapper.state('firstNumber')).toEqual(''); }); });
- В первом тесте в разделе «‹Form› взаимодействий» мы моделируем событие в поле ‹input›. Мы моделируем метод onChange в ‹input›, который имеет идентификатор ‘number1’. Мы присваиваем значение number1 ‹input› как 50. Если вы отметите функцию onChange для number1 в Файл Form.js вызывает метод handleFirstNumber (), как показано ниже.
handleFirstNumber(event) { this.setState({ firstNumber: event.target.value }); }
- Итак, согласно нашему тесту, он устанавливает 50 в качестве значения number1 и ожидает, что эта функция автоматически изменит значение state.firstNumber в Form.js до 50. Этот тест пройден, это означает, что мы успешно смоделировали метод onChange для number1.
- Во втором тесте мы делаем то же самое для имитации метода onChange в number2 ‹input›.
- Давайте добавим еще 2 теста, как показано ниже, и запустим файл.
it('should call the onClick function when \'Add\' button is clicked when the operator is \'+\'', () => { wrapper.setProps({ operator: '+' } ); const mockedHandleClickAdd = jest.fn(); wrapper.instance().handleAdd = mockedHandleClickAdd; wrapper.find('#formButtonAdd').props().onClick(); expect(mockedHandleClickAdd).toHaveBeenCalledTimes(1); }); it('should call the onClick function when \'Subtract\' button is clicked when the operator is \'-\'', () => { wrapper.setProps({ operator: '-' } ); const mockedHandleClickSubtract = jest.fn(); wrapper.instance().handleSubtract = mockedHandleClickSubtract; wrapper.find('#formButtonSubtract').props().onClick(); expect(mockedHandleClickSubtract).toHaveBeenCalledTimes(1); });
- В третьем тесте в разделе «‹Form› взаимодействий» имитируется функция onClick для ‹button› с идентификатором 'formButtonAdd'. . В Form.js при щелчке по нему должна быть вызвана функция с именем handleAdd (). Поскольку мы имитировали это, используя шутливую функцию с именем mockedHandleClickAdd (), вместо нее необходимо вызвать ее. Итак, наш тест прошел. Значит, мы успешно высмеяли функцию onClick в formButtonAdd.
- Точно так же в четвертом тесте мы имитируем функцию onClick для ‘formButtonSubtract’.
Шаг 3 - Написание тестов для вызовов методов жизненного цикла
- Добавьте еще один тест в вызовы методов жизненного цикла ‹Form› в Form.test.js, как показано ниже, и снова запустите файл.
describe('<Form /> lifecycle method invocations', () => { it('should change the state componentState componentDidMount method is invoked', () => { expect(wrapper.state('componentState')).toEqual('mounted'); }); });
- Здесь мы проверяем состояние с именем componentState, которое определено в файле Form.js. Согласно Form.js, состояние componentState будет изменено на «смонтировано» при вызове метода componentDidMount. Наш тест пройден, это означает, что метод componentMount вызван успешно.
Полный тестовый файл - Form.test.js
import Form from '../src/components/Form'; let wrapper; beforeEach(() => { wrapper = shallow(<Form/>); }); describe('<Form /> rendering', () => { it('should render one <form>', () => { expect(wrapper.find('form')).toHaveLength(1); }); it('should not render any <button> when operator is not passed in props', () => { expect(wrapper.find('button')).toHaveLength(0); }); it('should render 2 <label>s', () => { expect(wrapper.find('label')).toHaveLength(2); }); it('should render 2 <input>s', () => { expect(wrapper.find('input')).toHaveLength(2); }); it('should render one <button> to Add when operator \'+\' is passed in props', () => { wrapper.setProps({ operator: '+' } ); expect(wrapper.find('#formButtonAdd')).toHaveLength(1); expect(wrapper.find('#formButtonSubtract')).toHaveLength(0); }); it('should render one <button> to Subtract when operator \'-\' is passed in props', () => { wrapper.setProps({ operator: '-' } ); expect(wrapper.find('#formButtonAdd')).toHaveLength(0); expect(wrapper.find('#formButtonSubtract')).toHaveLength(1); }); }); describe('<Form /> interactions', () => { it('should change the state firstNumber when onChange function of the #number1 input is invoked', () => { wrapper.find('#number1').simulate('change', { target: { value: 50 } } ); expect(wrapper.state('firstNumber')).toEqual(50); expect(wrapper.state('secondNumber')).toEqual(''); }); it('should change the state secondNumber when onChange function of the #number2 input is invoked', () => { wrapper.find('#number2').simulate('change', { target: { value: 60 } } ); expect(wrapper.state('secondNumber')).toEqual(60); expect(wrapper.state('firstNumber')).toEqual(''); }); it('should call the onClick function when \'Add\' button is clicked when the operator is \'+\'', () => { wrapper.setProps({ operator: '+' } ); const mockedHandleClickAdd = jest.fn(); wrapper.instance().handleAdd = mockedHandleClickAdd; wrapper.find('#formButtonAdd').props().onClick(); expect(mockedHandleClickAdd).toHaveBeenCalledTimes(1); }); it('should call the onClick function when \'Subtract\' button is clicked when the operator is \'-\'', () => { wrapper.setProps({ operator: '-' } ); const mockedHandleClickSubtract = jest.fn(); wrapper.instance().handleSubtract = mockedHandleClickSubtract; wrapper.find('#formButtonSubtract').props().onClick(); expect(mockedHandleClickSubtract).toHaveBeenCalledTimes(1); }); }); describe('<Form /> lifecycle method invocations', () => { it('should change the state componentState componentDidMount method is invoked', () => { expect(wrapper.state('componentState')).toEqual('mounted'); }); });
Специальное примечание о «componentDidMount»
Предположим, у вас есть вызов базы данных в одном из методов жизненного цикла (componentDidMount или любом другом). Если вы вызовете его из тестов, он определенно потерпит неудачу, потому что у вас нет соединения с базой данных во время тестирования. Итак, решение для этого - использовать функцию прототипа componentDidMount, которая определена в вашем тестовом файле, как показано ниже.
beforeAll(() => { Form.prototype.componentDidMount = () => { console.log('componentDidMount method is called'); }; });
Заключение
Надеюсь, вы получили четкое представление о написании тестов пользовательского интерфейса для рендеринга, взаимодействия и вызовов методов жизненного цикла с использованием Jest и Enzyme.
Вы можете найти работу, которую мы проделали в этом руководстве, в ветке под названием tutorial-05 в репозитории git ниже.
wasuradananjith / testing-demo-app
Это исходный код для серии руководств« Тестирование с помощью Jest и Enzyme в React … github.com»
В следующем руководстве я рассмотрю «Тестирование снимков в Jest». А пока, до свидания!
Предыдущие уроки
Тестирование с помощью Jest и Enzyme in React - Часть 2 (Как интегрировать Enzyme с Jest в тестировании?)
В предыдущем руководстве мы узнали« Как настроить и запустить протестировать с помощью Jest? . В этом руководстве мы узнаем Как… medium.com
Эта история публикуется в Noteworthy, куда ежедневно приходят более 10 000 читателей, чтобы узнать о людях и идеях, формирующих наши любимые продукты.
Подпишитесь на нашу публикацию, чтобы увидеть больше историй о продуктах и дизайне, представленных командой Journal.