Никогда не писали автотесты? Попробуйте Cypress
Прежде всего хочу отметить, что я не профессиональный автотестер, а Java-программист. Но однажды поступила задача сделать smoke тесты для базовой проверки основных функций приложения, которое недавно поломали изменением в API зависимого сервиса без предупреждения.
Статья будет интересна всем, кто интересовался автотестированием с нуля на JS, но боялся спросить.
Начну с того, что по автотестированию я ничего никогда не читал. Основной преконсепшн был, что автотесты это сложно, потому что по отзывам пока этот Selenium настроишь... Плюс надо учить XPath и PageObject, чего делать вообще не хотелось.
Быстрый поиск по интернету дал более молодые и перспективные инструменты: WebDriver.IO, Pupeteer (а сейчас лучше Playwright) и Cypress. Выбрал последний, купился на красивые обещания и несколько комментов из холиваров по лучшим инструментам для автотестов.
Так выглядит окно браузера запущенного теста. Слева выполненные команды теста и статус, справа просмотр приложение во время исполнения теста:

Вот так выглядит код теста (в Cypress — весь код на JS, а селекторы — это обычные CSS селекторы):

В runtime выглядит так:

Пока искал инструмент для автотестов — в голове у меня была картинка, что тесты можно создавать прямо в браузере, чтобы просто «нажал на запись скрипта» — система записала мои действия (CSS селекторы элементов, на которые я нажимал). Потом я смотрю сгенерированный тест, подправляю селекторы если нужно, и сохраняю в Test Suite. Эх...
Сказка оказалась тогда недостижимой и таких инструментов я не нашел (возможно кто-то в комментах подскажет правильный путь). Но в Cypress подкупило то, что тесты выполняются в настоящем браузере, и даже можно параллельно с выполнением теста исследовать DOM любимыми инструментами разработчика Chrome (если например селектор не сработал — можно открыть консоль и сразу при исполнении теста посмотреть почему).

Из других параметров, которые для меня были важны — я критически не хотел тратить много времени ни на написание (опять про запись теста в браузере), ни на поддержку тестов. Для моих целей этого было вполне достаточно. Просто для информации o Cypress: с момента, как я впервые открыл сайт Cypress, до первого теста, который логинится в приложение — прошел 1 час.
Итак, Cypress, первая страница фреймворка говорит нам что это JavaScript End to End Testing Framework (cypress.io). Далее бегло читаем документацию, она действительно полная, и можно найти ответы практически на все вопросы (все остальное я быстро находил на StackOverflow):

Дальше по списку фичей с сайта:
- Time travel — каждый шаг выполнения теста в консоли — можно нажать и вернуться на конкретное состояние всего приложения в прошлом, которое отображается прямо в браузере. И это не просто записанная картинка, а реальный DOM, можно откатиться и исследовать страницу через Chrome devtools.
- Real time reloads — как во всей модерн JS теме, поменяли исходники — в тот же момент произошёл перезапуск теста в браузере (hot reload).
- Automatic waiting — многие инструкции теста асинхронные, как то переход на страницу, и Cypress сам автоматически дожидается окончания загрузки. Кроме конечно момента, когда вызовы сервера делает приложение.
- Network traffic control — Cypress может захватывать/видеть вызовы сервера и можно задать инструкцию, чтобы подождать ответ от сервера.
- Screenshots and videos — во время выполнения теста Cypress записывает видео экрана (MP4) браузера, вместе с инструкциями в окне.
Все это добро конечно же можно запускать и без открытого браузера на CI, используется headless Chrome или Electron.
Но были и некоторые проблемы.
По началу я не знал, что можно ждать окончания XHR запросов на сервер, и вставлял вместо них timeouts, и тесты рандомно падали. Поправил.

Потом через раз работал Hot Reload, постоянно приходилось перезапускать весь Cypress, потому что не было уверенности, что мои изменения применились. Оказалось, что в моей IDE (IntelliJ IDEA) есть такие нехорошие галочки, которые еще и включены по умолчанию, из-за которых получается что сохранение файла — это не сохранение, а eventual сохранение.

Следующая проблема была в том, что мое приложение использовало window fetch для запросов на сервер, а Cypress видит только XHR запросы. Dirty hack из StackOverflow помог (я так понял, что метод fetch удаляется из window, чтобы браузер сделал fallback на XHR вместо fetch):

Далее встала проблема эмуляции мобильного браузера, просто в коде теста user agent перезаписать не получилось, но в отдельном специальном файле — все получилось.

Далее решение CORS—проблемы:

Потом file upload, с наскоку не получилось, стандартные решения не сработали, зато помогла библиотека cypress-file-upload:

Единственная проблема которую я не смог решить — это воспроизводимость теста. А именно стабильные и одинаковые начальные данные для запуска теста (fixtures), это более конфигурационная задача, а не Cypress, но все равно пока нерешенная.
В итоге, Cypress выглядит отличным инструментом для внедрения автотестирования в проект, если:
- Есть знание JS
- Нет необходимости тестировать во всех видах браузеров начиная с IE6 (на данный момент Cypress поддерживает Chrome, Chromium, Edge, Electron, Firefox). Вот обсуждение темы. Но могу сказать, что год назад, когда я начинал работать с Cypress он поддерживал только последнюю версию Chrome и Electron для запусков без UI.
- Хотите быстро сделать тесты и забыть о них, пока кто-то не сломает приложение :)
Cypress: берите и пользуйтесь!
28 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарівВ кипарисе столкнулся с первым минусом — отсутствие оператора IF. И сделал вывод, что это показатель, что он (пока?) не для профессионалов.
П.С. дада, я читал в документации, что надо строить тесты так, чтобы он не понадобился, но это лишает удобства и занимает больше времени. А в моей проблеме (был отдельный топик на доу) — еще и невозможно.
У разработчиков Cypress свое мнение о Conditional testing. Но в принципе IF есть.
Год назад, примерно, сталкивался с этой проблемой и читал их «мнение». Но мою проблему это не решило. «Костыль» из интернета тоже не помог.
А разве Javascript-ового if-a не достаточно? Или вы про какую-то специальную реализацию if-a говорите?
Он не работает(-ал). В доках об этом написано.
Скорее он работает немного не так, как ожидалось на первый взгляд. Выше вы привели ссылку на тему, которую вы создавали. Там проблема не с if-ом. Он-то как раз честно сработал. Тут нужно учитывать особенности дизайна Cypress, по которому каждая команда возвращает какой-то Chainable объект. Из-за этого, в частности, не рекомендуется делать что-то типа:
let myObject = cy.get('some_selector'); myObject.click();В свое время намучался с такой гадостью. А так if-ы вполне используются, особенно если они применены к обычным переменным, а не к результатам работы команд Cypress.в моем случае хватило
cy.get('body').then(($body) => { // synchronously query from body // to find which element was created if ($body.find('input').length) { // input was found, do something else here return 'input' } })docs.cypress.io/...ng.html#Element-existencexunitpatterns.com/...nditional Test Logic.html
Госпаде, зачем это всё, 100500 фреймворков — Cypress, Playwright, Puppeteer, Selenide JS, Webdriver IO. Лучше взять джаву и голый селениум и не париться с всей этой дичью. В том же сайпресе, на сколько я помню, нужно платить за то что бы параллельно гнать тесты. В java + testng, что реран тестов что параллельный запуск настроить это 1 строчка.
Платити не потрібно, дешборд — це звичайна репортилка, ліл.
«Лучше» — суб’єктивне поняття. У кожного інструмента є свої хороші та погані сторони.
Cypress отличный инструмент, с большим комьюнити, и хорошей документацией
Отличный инструмент, после основанного на Selenium протрактора как глоток свежего воздуха.
*пустил слюну* было бы вообще шикарно
так такое есть уже medium.com/...r-and-faster-6ed70b712bff
спасибо за ссылку! на вид сгенерированный код хорошее начало, если бы ещё ожидание сервера были, хотя в принципе гитхаб есть
ожидание сервера всмысле ответа сервера? можно сделать cy.route({ method: «post», url: «/endpoints/logs/*» }).as("logs«); а потом cy.wait(’@logs’) и будет что надо :) не забыть установить флаг в конфиге «experimentalFetchPolyfill»: true,
с вас $3 за консультацию ;)
3$ с каждого кто прочитает?) хороший бизнес план
Serenity, Selenide взагалі норм штуки. Дивний вибір для джавіста. Хіба шо погратись
В джаві це можна реалізувати за допомогою анотацій тестових фреймворків на методи:
— для JUnit5 це — @ParameterizedTest
— для TestNG це — @DataProvider i @Factory
Ну з чистим Selenium WebDriver дійсно нелегко з нуля розібратись, але не дуже зрозуміло, чому вибрали саме JS-стек, раз ви джавіст, то в цьому випадку чудово підійде Selenide — selenide.org
Він під капотом вже має багато плюшок чистого Селеніума, які не потрібно знати і настроювати, і як і в Cypress, тест логіну за 15хв можна наконфігурити і все буде літати, код теж легкий для новачків, тим більше що для джава дева.
Можна обійтись і без XPath, знаю людей, які його не юзають. Можна юзати звичайні CSS selectors і в 90% випадків їх вистачає з головою.
Щодо РО — взагалі не зрозумів, що там вчити. Можливо розкажете в коментах більше детальніше, що ви мали на увазі.
Щодо
Дивіться на Selenium IDE, Katalon Studio, Ghost Inspector — це те, що зразу спало на думку. Але кажуть, що це не дуже good practice юзати такі тули, бо часто складні сценарії генерують не зовсім правильний код.
Це класно, але я б таке юзав досить рідко, імхо.
Selenide має це все під капотом також.
Навіть в чистому Селеніумі це робиться одним рядком:
driver.findElement(By.cssSelector("#someId")).sendKeys("C:\\path\to\your\file");No hate в сторону Cypress, але мені здається, що в цій ситуації ви можете заюзати рішення описані вище, і це буде краще для вас.
А взагалі, все залежить від того, для чого ви вирішили почати писати автотести, яка ціль, що хочете ними добитись і тд.
юзаю тайм тревел і нетворк інспектор для дебагу постійно
юзаю релоуд для ТДД постійно
краще не буде, буде так само + витратиш час на міграцію
йому сподобався сайпресс — хай його використовує :)
пс а у селеніда є network stubbing?
прікольно, можливо, я б теж часто юзав, але зараз не попробувавши, мені здається, що рідко.
Хоча тайм тревел все ж таки, корисна фіча, її би юзав часто
мав на увазі, якщо б спочатку стартувати проект, то краще Selenide
хз
Это не от тестировщиков зависит, а от фронтов, как они дом организуют. Я видел документы, где легко одними цссселекторами обойтись, видел документы, где это невозможно.
hello world на спрингбуте тоже можно за 5 минут запустить, но без нормального изучения функционала фреймворка, нормальной работы не получится.
ну так, я це мав на увазі також, коли казав, що 90% випадків можна обійтись без XPath, якраз таки через побудову DOM-дерева.
погоджуюсь. тоді відповім більш розгорнуто — можна легко розібратись, як почати писати тести і як масштабувати, підтримувати, їх в майбутньому.
💆♂️ а з новою retry фічою то взагалі казка
Якщо вам потрібен зелений білд, але для цього доводиться ховати провтики тест дизайну / недостатнє знання інструмента / відсутність розуміння як він працює в браузері / флекі-баги самого додатку / нестабільний тестовий стенд за перезапусками — чого б одразу не писати `expect(true).to.be.true` і не паритись?
валідний коментар, і я скажу, що я теж думаю, це — антипаттерн. Але коли ви тільки починаєте проект і у вас чіткого уявлення немає як воно то буде працювати, то застосовуємо принцип MVP і Парето — і це працює ± нормально.
як перестане бути достатньо і в прод будуть баги просочуватись — будемо думати і якось фіксати тести а потім і самі фічі. А поки що — і так зійде ;)
У всех ассертов вроде бы как built-in retry механизм, еще до 5го Cypress
Після 5го також. Під ретраями мається на увазі перезапуск цілого тесту, а не конкретної команди.