Взгляд на популярную Testing Library с Nightwatch — и многое другое
Мы создадим подробный пример проекта React с Vite, а затем воспользуемся Nightwatch и Testing Library для тестирования этих компонентов. Мы используем Complex example, доступный в документах React Testing Library, написанный с помощью Jest.
В этом уроке мы рассмотрим следующее:
-
Установим новый проект React с помощью Vite, который также используется внутри Nightwatch для компонентного тестирования
-
Установим и сконфигурируем Nightwatch и Testing Library
-
Сымитируем API запросы с помощью плагина
@nightwatch/api-testingН -
Напишем комплексный React-компонентный тест, используя Nightwatch и Testing Library.
Шаг 0. Создание нового проекта
Для начала мы создадим новый проект с Vite:
npm init vite@latest
Выберите React и JavaScript при появлении запроса. Это создаст новый проект с React и JavaScript.
Шаг 1. Установка Nightwatch и Testing Library
Testing Library для React может быть установлена с помощью пакета @testing-library/react:
npm i @testing-library/react --save-dev
Чтобы установить Nightwatch, выполните команду инициализации:
npm init nightwatch@latest
Выберите React и JavaScript при появлении запроса. С помощью этого будет установлен nightwatch и плагин @nightwatch/react. Выберите браузер для установки драйвера. В этом примере мы будем использовать Chrome.
1.1. Установка плагина @nightwatch/testing-library
Начиная с версии 2.6, Nightwatch предоставляет свой плагин для использования запросов Testing Library. Потом он понадобится нам для написания нашего теста, поэтому давайте сейчас его установим:
npm i @nightwatch/testing-library --save-dev
1.2. Установка плагина @nightwatch/apitesting
Этот пример содержит заглушку сервера, которая необходима для тестирования компонента. Мы будем использовать встроенную заглушку сервера, которая поставляется с плагином @nightwatch/apitesting. Установим его с помощью следующей команды:
npm i @nightwatch/apitesting --save-dev
Шаг 2. Создание компонента Login
Мы будем использовать тот же компонент, что и в React Testing Library docs. Создаем новый файл src/Login.jsx и добавляем следующий код:
// login.jsx import * as React from 'react' function Login() { const [state, setState] = React.useReducer((s, a) => ({...s, ...a}), { resolved: false, loading: false, error: null, }) function handleSubmit(event) { event.preventDefault() const {usernameInput, passwordInput} = event.target.elements setState({loading: true, resolved: false, error: null}) window .fetch('/api/login', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ username: usernameInput.value, password: passwordInput.value, }), }) .then(r => r.json().then(data => (r.ok ? data : Promise.reject(data)))) .then( user => { setState({loading: false, resolved: true, error: null}) window.localStorage.setItem('token', user.token) }, error => { setState({loading: false, resolved: false, error: error.message}) }, ) } return ( <div> <form onSubmit={handleSubmit}> <div> <label htmlFor="usernameInput">Username</label> <input id="usernameInput" /> </div> <div> <label htmlFor="passwordInput">Password</label> <input id="passwordInput" type="password" /> </div> <button type="submit">Submit{state.loading ? '...' : null}</button> </form> {state.error ? <div role="alert">{state.error}</div> : null} {state.resolved ? ( <div role="alert">Congrats! You're signed in!</div> ) : null} </div> ) } export default Login
Шаг 3. Создание компонента Test
Один из основополагающих принципов Testing Library заключается в том, что тесты должны максимально походить на то, как пользователи взаимодействуют с приложением. При написании компонентных тестов в Nightwatch с использованием JSX нам нужно написать тест как компонентную историю, используя формат Component Story Format, декларативный формат, представленный Storybook.
Это позволяет нам писать тесты, сосредотачиваясь на том, как компонент используется, а не на том, как он реализован, что соответствует философии Testing Library. Подробнее об этом можно прочитать в документации Nightwatch docs.
Самое замечательное в использовании этого формата для написания наших тестов заключается в том, что мы можем использовать один и тот же код для написания историй для наших компонентов, которые могут быть использованы для документирования и демонстрации их в Storybook.
3.1. Тест входа с валидными данными
Создаем новый файл src/Login.spec.jsx и добавляем следующий код, который делает то же самое, что и комплексный пример, написанный с помощью Jest:
Чтобы визуализировать компонент с помощью JSX в Nightwatch, мы создаем некий экспорт для визуализированного компонента, при необходимости с набором реквизитов. Функции play и test используются для взаимодействия с компонентом и для верификации результатов.
-
playиспользуется для взаимодействия с компонентом. Он выполняется в контексте браузера, поэтому мы можем использовать объектscreenиз Testing Library для запроса DOM и запуска событий; -
testиспользуется для проверки результатов. Он выполняется в контексте Node.js, поэтому мы можем использовать объект Nightwatchbrowserдля запроса DOM и проверки результатов.
// login.spec.jsx import {render, fireEvent, screen} from '@testing-library/react' import Login from '../src/login' export default { title: 'Login', component: Login } export const LoginWithValidCredentials = () => <Login />; LoginWithValidCredentials.play = async ({canvasElement}) => { //fill out the form }; LoginWithValidCredentials.test = async (browser) => { // verify the results };
Добавление заглушки сервера
В примере используется заглушка сервера для имитации запроса логина. Мы будем использовать встроенную заглушку сервера, который идет с плагином @nightwatch/apitesting.
Для этого мы будем использовать хуки setup и teardown, которые мы можем написать прямо в тестовом файле. Оба хука выполняются в контексте Node.js.
Нам также необходимо установить конечную точку входа в http://localhost:3000/api/login в компоненте Login, который является URL-адресом заглушки сервера.
Завершаем файл теста
Полный файл теста будет выглядеть так:
// login.spec.jsx import {render, fireEvent, screen} from '@testing-library/react' import Login from '../src/Login' let server; const token = 'fake_user_token'; let serverResponse = { status: 200, body: {token} }; export default { title: 'Login', component: Login, setup: async ({mockserver}) => { server = await mockserver.create(); server.setup((app) => { app.post('/api/login', function (req, res) { res.status(serverResponse.status).json(serverResponse.body); }); }); await server.start(mockServerPort); }, teardown: async (browser) => { await browser.execute(function() { window.localStorage.removeItem('token') }); await server.close(); } } export const LoginWithValidCredentials = () => <Login />; LoginWithValidCredentials.play = async ({canvasElement}) => { //fill out the form fireEvent.change(screen.getByLabelText(/username/i), { target: {value: 'chuck'}, }); fireEvent.change(screen.getByLabelText(/password/i), { target: {value: 'norris'}, }); fireEvent.click(screen.getByText(/submit/i)) }; LoginWithValidCredentials.test = async (browser) => { const alert = await browser.getByRole('alert') await expect(alert).text.to.match(/congrats/i) const localStorage = await browser.execute(function() { return window.localStorage.getItem('token'); }); await expect(localStorage).to.equal(fakeUserResponse.token) };
Дебагинг
Одним из основных преимуществ использования Nightwatch для компонентного тестирования, помимо наличия того же API, доступного для end-to-end тестирования, является то, что мы можем запускать тесты в реальном браузере, а не в виртуальной DOM среде, такой как JSDOM.
Это позволяет нам использовать Chrome Dev Tools для отладки тестов.
Например, давайте пойдем дальше и добавим оператор debugger в функцию LoginWithValidCredentials.play:
LoginWithValidCredentials.play = async ({canvasElement}) => { //fill out the form fireEvent.change(screen.getByLabelText(/username/i), { target: {value: 'chuck'}, }); fireEvent.change(screen.getByLabelText(/password/i), { target: {value: 'norris'}, }); debugger; fireEvent.click(screen.getByText(/submit/i)) };
Теперь запустим тест с флагами --debug и --devtools
npx nightwatch test/login.spec.jsx --debug --devtools
Откроется новое окно Chrome с открытыми инструментами разработчика Dev Tools. Теперь мы можем установить точку останова в Dev Tools и пройтись по коду.
3.2. Тест логина с сервер исключением
Исходный пример из документации Testing Library также включает тест для случая, когда сервер выбрасывает исключение.
Попробуем написать то же самое в Nightwatch. На этот раз мы будем использовать только функцию test, так как мы также можем взаимодействовать с компонентом. Как мы упоминали ранее, функция test выполняется в контексте Node.js и получает в качестве аргумента объект Nightwatch browser.
Нам также потребуется обновить ответ заглушки сервера, чтобы он возвращал код состояния 500 и сообщение об ошибке. Этого легко добиться, написав тестовый хук preRender для истории компонента LoginWithServerException.
export const LoginWithServerException = () => <Login />; LoginWithServerException.preRender = async (browser) => { serverResponse = { status: 500, body: {message: 'Internal server error'} }; }; LoginWithServerException.test = async (browser) => { const username = await browser.getByLabelText(/username/i); await username.sendKeys('chuck'); const password = await browser.getByLabelText(/password/i); await password.sendKeys('norris'); const submit = await browser.getByText(/submit/i); await submit.click(); const alert = await browser.getByRole('alert'); await expect(alert).text.to.match(/internal server error/i); const localStorage = await browser.execute(function() { return window.localStorage.getItem('token'); }); await expect(localStorage).to.equal(token) };
Шаг 4. Запуск теста
Наконец, давайте запустим наш тест. Будет запущен LoginWithValidCredentials и LoginWithServerException компонент историй в Chrome.
npx nightwatch test/login.spec.jsx
Чтобы запустить тест, не открывая браузер, мы можем передать флаг --headless. Если все пойдет хорошо, вы должны увидеть следующий аутпут:
[Login] Test Suite ──────────────────────────────────── ℹ Connected to ChromeDriver on port 9515 (1134ms). Using: chrome (108.0.5359.124) on MAC OS X. Mock server listening on port 3000 Running <LoginWithValidCredentials> component: ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── [browser] [vite] connecting... [browser] [vite] connected. ✔ Expected element <LoginWithValidCredentials> to be visible (15ms) ✔ Expected element <DIV[id='app'] > DIV > DIV> text to match: "/congrats/i" (14ms) ✔ Expected 'fake_user_token' to equal('fake_user_token'): ✨ PASSED. 3 assertions. (1.495s) Running <LoginWithServerException> component: ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── [browser] [vite] connecting... [browser] [vite] connected. ✔ Expected element <LoginWithServerException> to be visible (8ms) ✔ Expected element <DIV[id='app'] > DIV > DIV> text to match: "/internal server error/i" (8ms) ✔ Expected 'fake_user_token' to equal('fake_user_token'): ✨ PASSED. 3 assertions. (1.267s) ✨ PASSED. 6 total assertions (4.673s)
Заключение
Вот и все! Вы можете найти полный код этого примера в репозитории GitHub.Не стесняйтесь заходить в Nightwatch Discord, если у вас есть какие-либо вопросы или отзывы.
Также хочу порекомендовать вам бесплатный урок от OTUS, в рамках которого мы узнаем что из себя представляет PlayWright. Почему автотестеры все чаще стали выбирать именно его? Ознакомимся с его документацией, подключим к тестовому проекту и попробуем его особенности на практике.
ссылка на оригинал статьи https://habr.com/ru/company/otus/blog/719266/
Добавить комментарий