Selenide Selenide - Andrei Solntsev http://ru.selenide.org/rss http://ru.selenide.org 2024-09-25T05:52:46+00:00 2024-09-25T05:52:46+00:00 1800 Вышла Selenide 7.5.0 <p>Давно не виделись, котаны!</p> <p>Последний пресс-релиз я писал в апреле. С тех пор мы выпустили <a href="https://github.com/selenide/selenide/milestones?state=closed">несколько релизов</a>, из которых самый объёмный - <a href="https://github.com/selenide/selenide/milestone/208?closed=1">7.4.0</a>.</p> <p>Но теперь по-любому пора обновиться на <a href="https://github.com/selenide/selenide/milestone/212?closed=1">Selenide 7.5.0</a>:</p> <ul> <li><a href="#new-configuration-for-every-browser">Открывать браузер с новой конфигурацией</a></li> <li><a href="#raise-bubbleable-events-from-selects">Починили события в селектах</a></li> <li><a href="#builder-methods-for-download-options">Укоротили API для скачивания файлов</a></li> <li><a href="#do-not-close-windows-when-downloading-file">Больше не закрываем окна при скачивании файлов</a></li> <li><a href="#do-not-catch-all-errors">Больше не ловим вообще все ошибки</a></li> <li><a href="#generate-error-details-during-error-construction">Починили кастомные обработчики ошибок</a></li> <li><a href="#update-dependencies">Обновили зависимости</a></li> <li><a href="#news">Новости</a></li> <li><a href="#statistics">Статистика</a></li> </ul> <p><br /></p> <h3 id="new-configuration-for-every-browser">Можно открывать браузер с новой конфигурацией</h3> <p>В Селениде есть один нюанс, неочевидный для начинающих: все настройки в классе <code class="language-plaintext highlighter-rouge">Configuration</code> - статические. Поменяешь настройку в одном тесте - она повлияет на остальные. Особенно это важно при запуске параллельных тестов.</p> <p>Это, так сказать, не бага, а фича: там собраны настройки, которые вроде как и не надо менять от теста к тесту. А те значения, которые реально могут быть разными, мы давно вынесли в параметры разных методов:</p> <ul> <li><code class="language-plaintext highlighter-rouge">$.click(usingJavaScript()); // вместо Configuration.clickViaJs = true</code></li> <li><code class="language-plaintext highlighter-rouge">$.download(using(PROXY)); // вместо Configuration.fileDownload = PROXY</code></li> </ul> <p>Подробнее об этом процессе я <a href="https://www.youtube.com/watch?v=iIIsZRHya-w&amp;ab_channel=DEVCLUB.EU">рассказывал здесь</a>.</p> <p>Но оставалась ещё одна настройка <code class="language-plaintext highlighter-rouge">Configuration.browserCapabilities</code>. Иногда нужно в разных тестах задавать разные капабилити - например, чтобы задавать имя видео в Selenoid.</p> <p>Строго говоря, это было возможно и раньше - просто запуская вебдрайвер из своего кода с любыми нужными настройками. Но теперь их можно задать прямо в методе <code class="language-plaintext highlighter-rouge">open</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Test</span> <span class="kt">void</span> <span class="nf">testWithoutProxy</span><span class="o">()</span> <span class="o">{</span> <span class="n">open</span><span class="o">(</span><span class="s">"/one"</span><span class="o">,</span> <span class="k">new</span> <span class="nc">SelenideConfig</span><span class="o">().</span><span class="na">proxyEnabled</span><span class="o">(</span><span class="kc">false</span><span class="o">).</span><span class="na">fileDownload</span><span class="o">(</span><span class="no">FOLDER</span><span class="o">));</span> <span class="nc">File</span> <span class="n">report</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#report"</span><span class="o">).</span><span class="na">download</span><span class="o">();</span> <span class="o">}</span> <span class="nd">@Test</span> <span class="kt">void</span> <span class="nf">testWithProxy</span><span class="o">()</span> <span class="o">{</span> <span class="n">open</span><span class="o">(</span><span class="s">"/two"</span><span class="o">,</span> <span class="k">new</span> <span class="nc">SelenideConfig</span><span class="o">().</span><span class="na">proxyEnabled</span><span class="o">(</span><span class="kc">true</span><span class="o">).</span><span class="na">fileDownload</span><span class="o">(</span><span class="no">PROXY</span><span class="o">));</span> <span class="nc">File</span> <span class="n">cv</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#cv"</span><span class="o">).</span><span class="na">download</span><span class="o">();</span> <span class="o">}</span> </code></pre></div></div> <p>Смотрите не злоупотребляйте.</p> <p>NB! Когда вы вызываете метод <code class="language-plaintext highlighter-rouge">open(url, config)</code>, а какой-то браузер уже открыт в этом потоке (предыдущим тестом), то селенид его закроет. Это может привести к замедлению ваших тестов из-за постоянного переоткрывания браузеров. Имейте в виду.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1372">issue 1372</a> и <a href="https://github.com/selenide/selenide/pull/2846">PR 2846</a>.</p> <p><br /></p> <h3 id="raise-bubbleable-events-from-selects">Починили события в селектах</h3> <p>В <a href="https://github.com/selenide/selenide/releases/tag/v7.4.2">Selenide 7.4.2</a> мы улучшили работу с селектами в Vue.js: стали кидать события <code class="language-plaintext highlighter-rouge">input</code> в дополнение к <code class="language-plaintext highlighter-rouge">change</code>. Но при этом мы случайно изменили сами события: они больше не “bubbleable”. Что сломало обработку селектов в каких-то других фреймворках (когда обработчик события <code class="language-plaintext highlighter-rouge">change</code> висит не на самом селекте, а на его родителе).</p> <p>В общем, теперь починили. Смело выбирайте опции в ваших любимых селектах любыми способами:</p> <ul> <li><code class="language-plaintext highlighter-rouge">$("#migrants").selectOption("Похищают домашних животных");</code></li> <li><code class="language-plaintext highlighter-rouge">$("#migrants").selectOptionContainingText("дят собак и кош");</code></li> <li><code class="language-plaintext highlighter-rouge">$("#migrants").selectOption(2);</code></li> <li><code class="language-plaintext highlighter-rouge">$("#migrants").selectOptionByValue("kill-ducks-from-parks");</code></li> </ul> <p>См. <a href="https://github.com/selenide/selenide/issues/2832">issue 2832</a> и <a href="https://github.com/selenide/selenide/pull/2835">PR 2835</a>.</p> <p><br /></p> <h3 id="builder-methods-for-download-options">Укоротили API для скачивания файлов</h3> <p>Чтобы скачать файл с расширением “.txt”, раньше надо было написать довольно длинное выражение:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">File</span> <span class="n">f</span> <span class="o">=</span> <span class="err">$</span><span class="o">.</span><span class="na">download</span><span class="o">(</span><span class="n">using</span><span class="o">(</span><span class="no">FOLDER</span><span class="o">).</span><span class="na">withFilter</span><span class="o">(</span><span class="n">withExtension</span><span class="o">(</span><span class="s">"txt"</span><span class="o">)));</span> </code></pre></div></div> <p>Теперь можно будет писать короче:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">DownloadOptions</span><span class="o">.</span><span class="na">file</span><span class="o">;</span> <span class="nc">File</span> <span class="n">f</span> <span class="o">=</span> <span class="err">$</span><span class="o">.</span><span class="na">download</span><span class="o">(</span><span class="n">file</span><span class="o">().</span><span class="na">withExtension</span><span class="o">(</span><span class="s">"txt"</span><span class="o">)));</span> </code></pre></div></div> <p>В целом алгоритм прост: пишешь <code class="language-plaintext highlighter-rouge">download(file().</code> - и после точки выскакивают доступные варианты.</p> <center> <img src="/images/2024/09/download-file.png" width="800" /> </center> <p>См. <a href="https://github.com/selenide/selenide/pull/2841">PR 2841</a>.</p> <p><br /></p> <h3 id="do-not-close-windows-when-downloading-file">Больше не закрываем окна при скачивании файлов</h3> <p>Тут вот какая история. В селениде есть 4 метода скачивания файлов (HTTPGET, FOLDER, PROXY, CDP), и два из них (FOLDER, PROXY) изначально работали по такому принципу:</p> <ol> <li>Кликает элемент</li> <li>Ждёт, пока появится новый файл</li> <li>Если после клика появилось новое окно/вкладка - закрывает его</li> <li>Возвращает файл</li> </ol> <p>И вот сейчас мы пришли к пониманию, что третий шаг вроде как и не нужен. Никто уже и не помнит, зачем он изначально был добавлен. ¯_(ツ)_/¯</p> <p>Теперь селенид не будет пытаться закрыть никаких окон. Если у вас с этим проблема - обращайтесь, обкашляем вопросик. :)</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2836">issue 2836</a> и <a href="https://github.com/selenide/selenide/pull/2840">PR 2840</a>.</p> <p><br /></p> <h3 id="do-not-catch-all-errors">Больше не ловим вообще все ошибки</h3> <p>И снова ломаем устои. :)<br /> <a href="https://www.youtube.com/watch?v=be_cTwayRQc&amp;ab_channel=FestGroup&amp;t=3m59s">Главный алгоритм Селенида</a> - это по сути try/catch внутри цикла (до достижения 4 секунд). И очень важный вопрос - какие именно ошибки ловить внутри этого try/catch.</p> <p>Много лет там стояло <code class="language-plaintext highlighter-rouge">catch (Error error)</code>. По всем канонам - плохая практика в Java. Никто уже точно не помнит, почему. Возможно, из-за Internet Explorer, который когда-то кидал <code class="language-plaintext highlighter-rouge">java.lang.Error</code> в случае невалидного XPath.</p> <p>А проблема в том, что этот <code class="language-plaintext highlighter-rouge">catch (Error error)</code> может скрывать серьёзные проблемы, при которых тест должен не ретраить в цикле, а сразу падать. Что-то в духе OutOfMemory error.</p> <p>В общем, теперь мы не ловим <code class="language-plaintext highlighter-rouge">Error</code> и надеемся, что ни у кого ничего не сломается, ибо Internet Explorer давно показывает веб-странички Пригожину и Кобзону.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2845">PR 2845</a>.</p> <p><br /></p> <h3 id="generate-error-details-during-error-construction">Починили кастомные обработчики ошибок</h3> <p>Ой, пофиг, лень расписывать. :)<br /> Если вы переопределяете класс <code class="language-plaintext highlighter-rouge">SelenideErrorFormatter</code>, читайте <a href="https://github.com/selenide/selenide/issues/2830">issue 2830</a> и <a href="https://github.com/selenide/selenide/pull/2839">PR 2839</a>.</p> <p><br /></p> <h3 id="update-dependencies">Обновили зависимости</h3> <ul> <li>bump BrowserUpProxy from 2.2.18 to 2.2.19</li> <li>bump dnsjava from 3.6.0 to 3.6.1</li> <li>bump LittleProxy from 2.2.4 to 2.3.0 (#2837)</li> </ul> <p><br /></p> <h3 id="news">Новости</h3> <ul> <li>Мой видос <a href="https://www.youtube.com/watch?v=roL1ciaNWtY&amp;list=PL9Z-JgiTsOYRJCXuEOGXLH1w1oImoprnq&amp;ab_channel=ConfEngine">How to migrate from Selenium to Selenide for more stable tests!</a> с SeleniumConf 2024</li> <li>Мой видос <a href="https://www.youtube.com/watch?v=CKSl2NRrMVg">Selenide: Enjoy Writing Automated Tests for Mobile &amp; Web</a> с Testμ 2024 (LambdaTest)</li> <li>Мой видос <a href="https://www.youtube.com/watch?v=-TvVCxmb9ss&amp;ab_channel=EpicHey">How to debug autotests</a> с конференции EpicHey 2023</li> <li>Статьё <a href="https://www.testdevlab.com/blog/selenium-or-selenide-which-testing-framework-best-fits-your-needs">Selenium or Selenide: Which Testing Framework Best Fits Your Needs?</a></li> <li>Статьё <a href="https://qameta.io/blog/cleaning-up-e2e">Test smells: cleaning up E2E tests</a> by Natalia Poliakova, Mikhail Lankin</li> <li>Видос <a href="https://www.youtube.com/watch?v=j-uaUwoo90k&amp;ab_channel=JoseDiaz">про Селенид на испанском!</a> by Jose Diaz</li> <li>И ещё <a href="https://www.youtube.com/watch?v=zDw0iGdSghY&amp;ab_channel=TechProEducationTR">на турецком!</a> by Ahmet Bayram Ders</li> <li>Введение <a href="https://www.youtube.com/watch?v=scJFh0sKrXI">Selenide для QA Auto. Что такое Selenide?</a> на канале QA Automation и SDET</li> <li>То же, <a href="https://dzen.ru/shorts/66bf4d3b0bbae93b741dd7be?share_to=link">вид из шортов</a></li> <li>И наконец-то про коммиты на английском: <a href="https://www.youtube.com/watch?v=j-wfc5LVxM4">WTF Commit messages</a></li> </ul> <p><br /></p> <h3 id="statistics">Статистика</h3> <p>Количество скачиваний побило новый рекорд - 1.154.002 за август!</p> <center> <img src="/images/2024/09/selenide.downloads.png" width="800" /> </center> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2024/09/15/selenide-7.5.0/ http://ru.selenide.org/2024/09/15/selenide-7.5.0 2024-09-15T00:00:00+00:00 Вышла Selenide 7.3.1 <p>Добро утро!</p> <p>Мы выпустили <a href="https://github.com/selenide/selenide/milestone/205?closed=1">Selenide 7.3.1</a>.</p> <p>Релиз небольшой, так что обновиться будет прям легко. Приступаем к распаковке:</p> <ul> <li><a href="#mock-specific-content-type">Мокать ответ сервера заданного типа</a></li> <li><a href="#fix-clear-in-appium">Исправили метод <code class="language-plaintext highlighter-rouge">$.clear()</code> в мобилках</a></li> <li><a href="#fix-error-message-for-invalid-link">Исправили сообщение при клике на некорректную ссылку</a></li> <li><a href="#disable-warning-about-stolen-password">Отключили предупреждение Хрома про сворованные пароли</a></li> <li><a href="#fix-cdp-download-for-custom-webdrivers">Исправили загрузку файлов через CDP для кастомных вебдрайверов</a></li> <li><a href="#deprecate-setting-hold-browser-open">Задеприкейтили настройку <code class="language-plaintext highlighter-rouge">holdBrowserOpen</code></a></li> <li><a href="#upgrade-to-selenium-4.20.0">Обновили Selenium с 4.19.1 до 4.20.0</a></li> <li><a href="#statistics">Статистика</a></li> </ul> <p><br /></p> <h3 id="mock-specific-content-type">Мокать ответ сервера заданного типа</h3> <p>Как вы помните, Селенид позволяет через прокси <a href="/2022/10/07/selenide-6.9.0/#proxy-mock-response">подменить ответ сервера</a>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">getSelenideProxy</span><span class="o">().</span><span class="na">responseMocker</span><span class="o">().</span><span class="na">mockText</span><span class="o">(</span><span class="s">"cik-mock"</span><span class="o">,</span> <span class="n">urlStartsWith</span><span class="o">(</span><span class="no">GET</span><span class="o">,</span> <span class="s">"https://cik.ru/api/gov/no/referendum"</span><span class="o">),</span> <span class="o">()</span> <span class="o">-&gt;</span> <span class="s">"{votes: 2133326, for: 99.23, against: 0.77}"</span><span class="o">);</span> </code></pre></div></div> <p>Но при этом невозможно было задать тип контента (xml, json и т.п.). А иногда это важно. Теперь можно задать любые заголовки для ответа сервера, в т.ч. <code class="language-plaintext highlighter-rouge">Content-Type</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">org.openqa.selenium.remote.http.HttpResponse</span><span class="o">;</span> <span class="n">getSelenideProxy</span><span class="o">().</span><span class="na">proxyMocker</span><span class="o">().</span><span class="na">mockResponse</span><span class="o">(</span><span class="s">"cik-mock"</span><span class="o">,</span> <span class="n">urlStartsWith</span><span class="o">(</span><span class="no">GET</span><span class="o">,</span> <span class="s">"https://cik.ru/api/gov/no/referendum"</span><span class="o">),</span> <span class="o">()</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nc">HttpResponse</span><span class="o">()</span> <span class="o">.</span><span class="na">setStatus</span><span class="o">(</span><span class="mi">429</span><span class="o">)</span> <span class="o">.</span><span class="na">addHeader</span><span class="o">(</span><span class="s">"Content-Type"</span><span class="o">,</span> <span class="s">"application/json"</span><span class="o">)</span> <span class="o">.</span><span class="na">setContent</span><span class="o">(</span><span class="n">utf8String</span><span class="o">(</span><span class="s">"{votes: 2133326, for: 99.23, against: 0.77}"</span><span class="o">))</span> <span class="o">);</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2705">issue 2705</a> и <a href="https://github.com/selenide/selenide/pull/2706">PR 2706</a>.</p> <p><br /></p> <h3 id="fix-clear-in-appium">Исправили метод <code class="language-plaintext highlighter-rouge">$.clear()</code> в мобилках</h3> <p>… для элемента, который существует, но невидим.</p> <p>Оказывается, что вызов <code class="language-plaintext highlighter-rouge">clear</code> или <code class="language-plaintext highlighter-rouge">click</code> в мобилках:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#hiddenElement"</span><span class="o">).</span><span class="na">clear</span><span class="o">();</span> </code></pre></div></div> <p>Падал с некорректным сообщением, если элемент найден, но невидим (например, перекрыт другим элементом):</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Element</span> <span class="n">should</span> <span class="n">be</span> <span class="n">interactable</span> <span class="o">{</span><span class="nc">By</span><span class="o">.</span><span class="na">name</span><span class="o">:</span> <span class="nc">ComputeSumButton</span><span class="o">}</span> <span class="nl">Element:</span> <span class="err">'</span><span class="o">&lt;</span><span class="nc">XCUIElementTypeButton</span> <span class="o">...</span> <span class="n">visible</span><span class="o">=</span><span class="s">"false"</span><span class="o">&gt;...</span> <span class="nc">Caused</span> <span class="nl">by:</span> <span class="nl">UnsupportedCommandException:</span> <span class="nc">Unhandled</span> <span class="nl">endpoint:</span> <span class="o">/</span><span class="n">session</span><span class="o">/</span><span class="mi">28</span><span class="o">...</span><span class="mi">13</span><span class="o">/</span><span class="n">element</span><span class="o">/</span><span class="mo">07000000</span><span class="o">-</span><span class="mo">0000</span><span class="o">-</span><span class="mo">0000</span><span class="o">-</span><span class="no">CF35</span><span class="o">-</span><span class="mo">000000000000</span><span class="o">/</span><span class="n">css</span><span class="o">/</span><span class="n">opacity</span> <span class="o">...</span> </code></pre></div></div> <p>Теперь сообщение будем корректным, без всяких там <code class="language-plaintext highlighter-rouge">UnsupportedCommandException</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Element</span> <span class="n">should</span> <span class="n">be</span> <span class="n">visible</span> <span class="o">{</span><span class="nc">By</span><span class="o">.</span><span class="na">name</span><span class="o">:</span> <span class="nc">ComputeSumButton</span><span class="o">}</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2722">issue 2722</a> и <a href="https://github.com/selenide/selenide/pull/2723">PR 2723</a>.</p> <p><br /></p> <h3 id="fix-error-message-for-invalid-link">Исправили сообщение при клике на некорректную ссылку</h3> <p>Похожая проблема. Если в Firefox попытаться кликнуть на некорректную ссылку (например, <code class="language-plaintext highlighter-rouge">https://zopa</code>):</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"#invalid-link"</span><span class="o">)</span> <span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">attribute</span><span class="o">(</span><span class="s">"href"</span><span class="o">,</span> <span class="s">"https://zopa"</span><span class="o">))</span> <span class="o">.</span><span class="na">click</span><span class="o">();</span> </code></pre></div></div> <p>то Селенид выдавал некорректное сообщение об ошибке:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Element</span> <span class="n">not</span> <span class="n">found</span> <span class="o">{</span><span class="err">#</span><span class="n">link</span><span class="o">}</span> <span class="nl">Expected:</span> <span class="nl">clickable:</span> <span class="n">interactable</span> <span class="n">and</span> <span class="n">enabled</span> </code></pre></div></div> <p>Теперь будет честный текст ошибки:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">WebDriverException:</span> <span class="nc">Reached</span> <span class="n">error</span> <span class="nl">page:</span> <span class="nl">about:</span><span class="n">neterror</span><span class="o">?</span><span class="n">e</span><span class="o">=</span><span class="n">dnsNotFound</span><span class="o">&amp;</span><span class="n">u</span><span class="o">=</span><span class="n">https</span><span class="o">%</span><span class="mi">3</span><span class="no">A</span><span class="c1">//zopa/</span> <span class="nc">Build</span> <span class="nl">info:</span> <span class="nl">version:</span> <span class="err">'</span><span class="mf">4.20</span><span class="o">.</span><span class="mi">0</span><span class="err">'</span><span class="o">,</span> <span class="nl">revision:</span> <span class="err">'</span><span class="mi">866</span><span class="n">c76ca80</span><span class="err">'</span> </code></pre></div></div> <p>P.S. Интересно, что такую ошибку выдаёт только Firefox. Остальные браузеры спокойно показывают стандартную страницу с текстом:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>This site can’t be reached Check if there is a typo in example. DNS_PROBE_FINISHED_NXDOMAIN </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2725">issue 2725</a> и <a href="https://github.com/selenide/selenide/pull/2727">PR 2727</a>.</p> <p><br /></p> <h3 id="disable-warning-about-stolen-password">Отключили предупреждение Хрома про сворованные пароли</h3> <p>Снова. Уже отключали в <a href="https://github.com/selenide/selenide/pull/2662">PR 2662</a>, но там мы добавили настройку <code class="language-plaintext highlighter-rouge">profile.password_manager_enabled=false</code>, и этого оказалось мало. Теперь докинули ещё и настройку <code class="language-plaintext highlighter-rouge">profile.password_manager_leak_detection=false</code>.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2729">PR 2729</a>.</p> <p><br /></p> <h3 id="fix-cdp-download-for-custom-webdrivers">Исправили загрузку файлов через CDP для кастомных вебдрайверов</h3> <p>Как вы помните, несколько месяцев назад вы реализовали новый способ скачивания файлов через CDP. Работает он только в Chromium-based браузерах (Chrome, Edge etc.).</p> <p>Но вот в случае кастомного вебдрайвера проверка “а хром ли это” не срабатывала:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Configuration</span><span class="o">.</span><span class="na">fileDownload</span> <span class="o">=</span> <span class="no">CDP</span><span class="o">;</span> <span class="nc">Configuration</span><span class="o">.</span><span class="na">browser</span> <span class="o">=</span> <span class="nc">MyCustomChromedriverFactory</span><span class="o">.</span><span class="na">class</span><span class="o">.</span><span class="na">getName</span><span class="o">();</span> <span class="nc">File</span> <span class="n">report</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#report"</span><span class="o">).</span><span class="na">download</span><span class="o">();</span> <span class="c1">// летела ошибка: java.lang.IllegalArgumentException: </span> <span class="c1">// The browser you selected "MyTest$CustomWebDriverProvider" doesn't have Chrome Devtools protocol functionality.</span> </code></pre></div></div> <p>Теперь селенид правильно распознаёт Chromium-based браузеры по их реальным капабилитям. Обожаю это слово. :)</p> <p>Спасибо <a href="https://github.com/PetroOv">Petr Ovcharenko</a> за <a href="https://github.com/selenide/selenide/pull/2728">PR 2728</a>.</p> <p><br /></p> <h3 id="deprecate-setting-hold-browser-open">Задеприкейтили настройку <code class="language-plaintext highlighter-rouge">holdBrowserOpen</code></h3> <p>Есть такой флажок в Селениде - если его установить, то Селенид не будет закрывать браузер после прогона тестов. Иногда люди хотят оставить браузер открытым, чтобы после теста поковыряться в нём, что-то там поизучать и поотлаживать.</p> <p>Лично мне никогда не нравилась эта фича, и я давно хотел её удалить. Но теперь появилась веская причина: внезапно мы осознали, что фича вредная. Когда вы поковыряетесь в браузере и закроете его руками, вебдрайвер-то никто уже не закроет, и он останется висеть в памяти и жрать ресурсы.</p> <p>Поэтому вместо <code class="language-plaintext highlighter-rouge">holdBrowserOpen</code> лучше напишите где-нибудь в своём тесте <code class="language-plaintext highlighter-rouge">sleep(600_000)</code> и ковыряйтесь на здоровье.</p> <blockquote> <p>Кто знает, почему именно 600 секунд? Олды тут?</p> </blockquote> <p>См. <a href="https://github.com/selenide/selenide/pull/2730">PR 2730</a>.</p> <p><br /></p> <h3 id="upgrade-to-selenium-4.20.0">Обновили Selenium с 4.19.1 до 4.20.0</h3> <p>В <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">ченджлоге Selenium</a>, честно говоря, больших изменений не вижу. Ну разве что добавили поддержку CDP 124 и убрали 121.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2726">PR 2726</a>.</p> <p><br /></p> <h3 id="statistics">Статистика</h3> <p>Случилось!!!</p> <p>Количество ежемесячных скачиваний Селенида перевалило за … <strong>миллион</strong>!</p> <center> <img src="/images/2024/04/selenide.downloads.png" width="600px" /> </center> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2024/04/28/selenide-7.3.1/ http://ru.selenide.org/2024/04/28/selenide-7.3.1 2024-04-28T00:00:00+00:00 Вышла Selenide 7.2.0 <p>Чёртов февраль.</p> <p>Чтобы хоть как-то отвлечься, попробуйте обновиться на <a href="https://github.com/selenide/selenide/milestone/201?closed=1">Selenide 7.2.0</a>:</p> <ul> <li><a href="#download-files-to-folder-in-selenium-grid">Скачиваем файлы из Selenium Grid</a></li> <li><a href="#download-files-remotely-with-cdp">Скачиваем файлы удалённо с помощью CDP</a></li> <li><a href="#mobile-elements-collections">Коллекции элементов для мобилок</a></li> <li><a href="#disable-chrome-warning-about-stolen-passwords">Выключили предупреждение хрома про покраденные пароли</a></li> <li><a href="#improve-error-message-for-download-without-href">Сообщение об ошибке, если нет href</a></li> <li><a href="#upgraded-to-selenium-4.18.1">Обновили Selenium с 4.17.0 на 4.18.1</a></li> </ul> <p><br /></p> <h3 id="download-files-to-folder-in-selenium-grid">Скачиваем файлы из Selenium Grid</h3> <p>Наконец-то! <br /> Теперь вы можете скачивать файлы методом <code class="language-plaintext highlighter-rouge">FOLDER</code> и из Selenium Grid.<br /> До сих пор <code class="language-plaintext highlighter-rouge">FOLDER</code> работал только при локальном запуске и в Selenoid.</p> <p>Если вы гоняете браузеры на Selenium Grid и хотите в тестах скачивать файлы методом <code class="language-plaintext highlighter-rouge">FOLDER</code>, вам просто нужно будет поменять зависимость</p> <div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">:</span><span class="nl">selenide:</span><span class="mf">7.1</span><span class="o">.</span><span class="mi">0</span> </code></pre></div></div> <p>на</p> <div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">:</span><span class="n">selenide</span><span class="o">-</span><span class="nl">grid:</span><span class="mf">7.2</span><span class="o">.</span><span class="mi">0</span> </code></pre></div></div> <p>И как бы в общем-то всё.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Configuration</span><span class="o">.</span><span class="na">remote</span> <span class="o">=</span> <span class="s">"https://qa.grid.my.com:4444/wd/hub"</span><span class="o">;</span> <span class="nc">Configuration</span><span class="o">.</span><span class="na">fileDownload</span> <span class="o">=</span> <span class="no">FOLDER</span><span class="o">;</span> <span class="nc">File</span> <span class="n">quotes</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#quotes"</span><span class="o">).</span><span class="na">download</span><span class="o">(</span><span class="n">withExtension</span><span class="o">(</span><span class="s">"txt"</span><span class="o">));</span> <span class="n">assertThat</span><span class="o">(</span><span class="n">quotes</span><span class="o">.</span><span class="na">content</span><span class="o">()).</span><span class="na">contains</span><span class="o">(</span> <span class="s">"Любовь сильнее страха"</span><span class="o">,</span> <span class="s">"Стыдно не делать ничего. Стыдно дать себя запугать."</span><span class="o">);</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1687">issue 1687</a>, <a href="https://github.com/selenide/selenide/pull/2659">PR 2659</a> и <a href="https://github.com/selenide/selenide/pull/2660">PR 2660</a>.</p> <p><br /></p> <h3 id="download-files-remotely-with-cdp">Скачиваем файлы удалённо с помощью CDP</h3> <p>В предыдущем релизе мы добавили новый метод скачивания файлов <a href="/2024/02/07/selenide-7.1.0/#download-files-with-cdp">CDP</a>, но работал он только локально.</p> <p>Теперь он также работает с удалёнными браузерами на Selenoid и Selenium Grid.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Configuration</span><span class="o">.</span><span class="na">remote</span> <span class="o">=</span> <span class="s">"https://cloud.browsers.my.com:4444/wd/hub"</span><span class="o">;</span> <span class="nc">Configuration</span><span class="o">.</span><span class="na">fileDownload</span> <span class="o">=</span> <span class="no">CDP</span><span class="o">;</span> <span class="nc">File</span> <span class="n">places</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#places"</span><span class="o">).</span><span class="na">download</span><span class="o">(</span><span class="n">withExtension</span><span class="o">(</span><span class="s">"csv"</span><span class="o">));</span> <span class="n">assertThat</span><span class="o">(</span><span class="n">places</span><span class="o">.</span><span class="na">content</span><span class="o">()).</span><span class="na">contains</span><span class="o">(</span><span class="s">"Утоли моя печали"</span><span class="o">,</span> <span class="s">"Борисовское"</span><span class="o">);</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1687">issue 1687</a>, <a href="https://github.com/selenide/selenide/issues/2550">issue 2550</a> и <a href="https://github.com/selenide/selenide/pull/2661">PR 2661</a>.</p> <p><br /></p> <h3 id="mobile-elements-collections">Коллекции элементов для мобилок</h3> <p>Мы навалили полезняшек для автотестов мобильных приложений. Появились новые методы для коллекций:</p> <ul> <li><code class="language-plaintext highlighter-rouge">SelenideAppium.$$(By)</code></li> <li><code class="language-plaintext highlighter-rouge">SelenideAppium.$$(Collection&lt;WebElement&gt;)</code></li> </ul> <p>Оба возвращают объект <code class="language-plaintext highlighter-rouge">SelenideAppiumCollection</code>. По сути это то же самое, что старый добрый <code class="language-plaintext highlighter-rouge">ElementsCollection</code>, только с объектами <code class="language-plaintext highlighter-rouge">SelenideAppiumElement</code> вместо <code class="language-plaintext highlighter-rouge">SelenideElement</code>.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">SelenideAppiumCollection</span> <span class="n">poetry</span> <span class="o">=</span> <span class="err">$$</span><span class="o">(</span><span class="nc">By</span><span class="o">.</span><span class="na">xpath</span><span class="o">(</span><span class="s">"//android.widget.EditText"</span><span class="o">)).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">size</span><span class="o">(</span><span class="mi">2</span><span class="o">));</span> <span class="n">poetry</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="mi">0</span><span class="o">).</span><span class="na">scroll</span><span class="o">(</span><span class="n">up</span><span class="o">()).</span><span class="na">setValue</span><span class="o">(</span><span class="s">"и в небо сорвутся тромбы"</span><span class="o">);</span> <span class="n">poetry</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="mi">1</span><span class="o">).</span><span class="na">scroll</span><span class="o">(</span><span class="n">down</span><span class="o">()).</span><span class="na">setValue</span><span class="o">(</span><span class="s">"багровых кремлёвских башен"</span><span class="o">);</span> </code></pre></div></div> <p>Также добавили метод <code class="language-plaintext highlighter-rouge">SelenideAppium.$(WebElement webElement)</code>, но вряд ли это вам пригодится.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2333">issue 2333</a> и <a href="https://github.com/selenide/selenide/pull/2656">PR 2656</a>.</p> <p><br /></p> <h3 id="disable-chrome-warning-about-stolen-passwords">Выключили предупреждение хрома про покраденные пароли</h3> <p>После обновления хрома начал выскакивать этот мешающий диалог “ваши пароли покрадены”. Кажется логичным, что в тестах он никому не нужен.</p> <p>И хотя это выглядит скорее как бага Chrome 122, мы на всякий случай его по-быстрому вырубили.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2658">issue 2658</a> и <a href="https://github.com/selenide/selenide/pull/2662">PR 2662</a>.</p> <p><br /></p> <h3 id="improve-error-message-for-download-without-href">Сообщение об ошибке, если нет <code class="language-plaintext highlighter-rouge">href</code></h3> <p>Меня внезапно осенило, почему так много людей мучаются с настройкой прокси и даже не догадываются, что в селениде есть и другие способы скачивания файлов: <code class="language-plaintext highlighter-rouge">FOLDER</code> и <code class="language-plaintext highlighter-rouge">CDP</code> (которые проще в использовании, а теперь ещё и полноценно работают с удалёнными браузерами).</p> <p>Возможно, проблема в коммуникации. Все эти годы метод <code class="language-plaintext highlighter-rouge">$.download()</code> кидал вот такую ошибку:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">The</span> <span class="n">element</span> <span class="n">does</span> <span class="n">not</span> <span class="n">have</span> <span class="n">href</span> <span class="nl">attribute:</span> <span class="o">&lt;</span><span class="n">a</span> <span class="n">id</span><span class="o">=</span><span class="s">"generate-report"</span><span class="o">&gt;</span> </code></pre></div></div> <p>После этого люди гуглили <a href="https://selenide.org/2019/12/10/advent-calendar-download-files/">первую попавшуюся статью</a> 5-летней давности, в которой, конечно, упоминалась только одна альтернатива - <code class="language-plaintext highlighter-rouge">PROXY</code>. И ломились изучать прокси.</p> <p>Теперь сообщение об ошибке будет подсказывать, что методов несколько:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">The</span> <span class="n">element</span> <span class="n">does</span> <span class="n">not</span> <span class="n">have</span> <span class="s">"href"</span> <span class="nl">attribute:</span> <span class="o">&lt;</span><span class="n">a</span> <span class="n">id</span><span class="o">=</span><span class="s">"generate-report"</span><span class="o">&gt;,</span> <span class="n">so</span> <span class="n">method</span> <span class="no">HTTPGET</span> <span class="n">cannot</span> <span class="n">download</span> <span class="n">the</span> <span class="n">file</span><span class="o">.</span> <span class="nc">Please</span> <span class="k">try</span> <span class="n">another</span> <span class="n">download</span> <span class="nl">method:</span> <span class="no">FOLDER</span><span class="o">,</span> <span class="no">CDP</span> <span class="n">or</span> <span class="no">PROXY</span><span class="o">.</span> <span class="nc">Read</span> <span class="n">more</span> <span class="n">about</span> <span class="n">possible</span> <span class="n">download</span> <span class="nl">methods:</span> <span class="nl">https:</span><span class="c1">//selenide.org/javadoc/current/com/codeborne/selenide/FileDownloadMode.html</span> </code></pre></div></div> <p>Правда, боюсь, это не поможет, потому что кто же их читает-то…</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2653">PR 2653</a>.</p> <p><br /></p> <h3 id="upgraded-to-selenium-4.18.1">Обновили Selenium с 4.17.0 на 4.18.1</h3> <p>См. <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">ченджлог Selenium</a> и <a href="https://github.com/selenide/selenide/pull/2655">PR 2655</a>.</p> <p><br /></p> <p>Будем надеяться на весну.</p> <p><br /></p> <blockquote> <p>Не сдавайтесь.<br /> Не унывайте и не опускайте руки.<br /> Автоматизация тестирования — это не спринт, а долгий тяжёлый марафон.</p> </blockquote> <center> <a href="https://www.youtube.com/watch?v=wp66e-JRlj0">Теперь далеко отсюда</a> </center> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2024/02/27/selenide-7.2.0/ http://ru.selenide.org/2024/02/27/selenide-7.2.0 2024-02-27T00:00:00+00:00 Вышла Selenide 7.1.0 <p>Всем привет! С Новым Годом, с новыми надеждами!</p> <p>Сегодня у нас в меню свеженький блестящий <a href="https://github.com/selenide/selenide/milestone/199?closed=1">Selenide 7.1.0</a>:</p> <ul> <li><a href="#download-files-with-cdp">Скачивание файлов с помощью CDP</a></li> <li><a href="#animated-condition">Условие <code class="language-plaintext highlighter-rouge">animated</code></a></li> <li><a href="#if-with-timeout">IF с таймаутом ¯¯_(ツ)_/¯¯</a></li> <li><a href="#force-click">Можно кликать задизейбленные элементы</a></li> <li><a href="#method-unfocus">Метод <code class="language-plaintext highlighter-rouge">$.unfocus()</code></a></li> <li><a href="#avoid-page-load-timeout-in-mobile">Исправили page load timeout в мобилках</a></li> <li><a href="#can-add-same-proxy-filter-many-times">Можно добавлять прокси фильтр многократно</a></li> <li><a href="#update-dependencies">Обновили зависимости</a></li> <li><a href="#statistics">Статистика</a></li> </ul> <p><br /></p> <h3 id="download-files-with-cdp">Скачивание файлов с помощью CDP</h3> <p>Не прошло и три года, как в Selenium завезли CDP, а мы уже сделали с помощью него скачивание файлов! Как вы знаете, скачивать файлы в селениде можно несколькими способами: <code class="language-plaintext highlighter-rouge">HTTPGET</code>, <code class="language-plaintext highlighter-rouge">FOLDER</code>, <code class="language-plaintext highlighter-rouge">PROXY</code>. Теперь к ним добавился ещё и <code class="language-plaintext highlighter-rouge">CDP</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Configuration</span><span class="o">.</span><span class="na">fileDownload</span> <span class="o">=</span> <span class="no">CDP</span><span class="o">;</span> <span class="nc">File</span> <span class="n">f</span> <span class="o">=</span> <span class="err">$</span><span class="o">.</span><span class="na">download</span><span class="o">();</span> </code></pre></div></div> <p>либо</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">File</span> <span class="n">f</span> <span class="o">=</span> <span class="err">$</span><span class="o">.</span><span class="na">download</span><span class="o">(</span><span class="n">using</span><span class="o">(</span><span class="no">CDP</span><span class="o">));</span> </code></pre></div></div> <p>Работает он примерно как <code class="language-plaintext highlighter-rouge">FOLDER</code>: кликает ссылку и ждёт, пока файл появится в списке скачанных. Только в отличие от <code class="language-plaintext highlighter-rouge">FOLDER</code>, <code class="language-plaintext highlighter-rouge">CDP</code> понимает, что загрузка завершена, не по дате файла, а по событию <code class="language-plaintext highlighter-rouge">Browser.downloadProgress</code> из CDP.</p> <p>Конечно, этот метод скачивания работает только в Chromium-браузерах. И пока только на локальном браузере.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2550">issue 2550</a>. Спасибо <a href="https://github.com/britka">Sergey Brit</a> за <a href="https://github.com/selenide/selenide/pull/2567">PR 2567</a>.</p> <hr /> <p>NB! Как контрибьютер, Сергей получает право рассказать вам о каком-то фонде на его выбор.</p> <p>Слово Сергею:</p> <blockquote> <p>Призываю вас донатить фонду <a href="https://www.angrycorgi.org/en">ANGRY CORGI</a>.</p> <p>Фонд Angry Corgi создан людьми из tech, чтобы усилить компьютерную инфраструктуру частей ПВО и ряду других частей Сил Обороны Украины. <br /> Фонд постоянно принимает технику из разных стран мира, а также собирает деньги на закупку планшетов, телевизоров и другого коммуникационного оборудования.</p> </blockquote> <p>Вот такая у нас теперь будет славная традиция. :)</p> <hr /> <p><br /></p> <h3 id="animated-condition">Условие <code class="language-plaintext highlighter-rouge">animated</code> для окончания анимации</h3> <p>Анимированные элементы могут доставить автоматизаторам немало неприятных моментов. Твой тест пытается кликнуть элемент - а он в этот момент куда-то двигается, сжимается, расширяется - чёрти что. И клик попадает по другому элементу.</p> <blockquote> <p>Подробнее об этом в видосе <a href="https://www.youtube.com/watch?v=zOiSo1hYjF8&amp;t=29m43s">Flaky tests</a>.</p> </blockquote> <p>Теперь можно дождаться окончания анимации с помощью такой вот команды:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">.</span><span class="na">shouldNotBe</span><span class="o">(</span><span class="n">animated</span><span class="o">);</span> </code></pre></div></div> <p>Надеемся, это поможет сделать ваши тесты более стабильными.</p> <p>Спасибо <a href="https://github.com/BorisOsipov">Boris Osipov</a> за <a href="https://github.com/selenide/selenide/pull/2556/files">PR 2556</a>.</p> <p>Вы спросите, а как же селенид понимает, что анимация закончилась? Загляните в пулреквест, это интересно. Если вкратце - с помощью JS функции <code class="language-plaintext highlighter-rouge">requestAnimationFrame</code> селенид спрашивает у браузера размеры и координаты элемента два раза подряд (в двух разных циклах отрисовки) и проверяет, что они не изменились. Хитро, а?</p> <p><br /></p> <h3 id="if-with-timeout">Добавили IF с таймаутом ¯¯_(ツ)_/¯¯</h3> <p>Много лет мы сопротивлялись, но всё-таки позволили этому случиться. :)</p> <p>Мы добавили метод <code class="language-plaintext highlighter-rouge">$.is(condition, timeout)</code>, который возвращает boolean. Теперь в своих тестах вы сможете писать ифы без try/catch. <a href="/2019/12/02/advent-calendar-how-to-abuse-selenide/">Ворота в ад разверзлись</a>.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">if</span> <span class="o">(</span><span class="err">$</span><span class="o">(</span><span class="s">"#banner"</span><span class="o">).</span><span class="na">is</span><span class="o">(</span><span class="n">visible</span><span class="o">,</span> <span class="nc">Duration</span><span class="o">.</span><span class="na">ofSeconds</span><span class="o">(</span><span class="mi">2</span><span class="o">)))</span> <span class="o">{</span> <span class="err">$</span><span class="o">(</span><span class="s">"#banner .close"</span><span class="o">).</span><span class="na">click</span><span class="o">();</span> <span class="o">}</span> </code></pre></div></div> <p>Логика этого ифа наверняка подпалит немало седалищ, так что будьте внимательны:</p> <ol> <li>Если элемент видимый, он сразу вернёт <code class="language-plaintext highlighter-rouge">true</code>.</li> <li>Если элемент невидимый, метод подождёт какое-то время (но не больше заданного таймаута), и если элемент появился - вернёт <code class="language-plaintext highlighter-rouge">true</code>.</li> <li>А вот если элемент так и не появился, в итоге вернёт <code class="language-plaintext highlighter-rouge">false</code>.</li> </ol> <p>См. <a href="https://github.com/selenide/selenide/issues/2590">issue 2590</a>.<br /> Вечный позор на <a href="https://github.com/asolntsev">мои седины</a> за <a href="https://github.com/selenide/selenide/pull/2640">PR 2640</a>!</p> <blockquote> <p>NB! Новый метод <code class="language-plaintext highlighter-rouge">$.is(.., Duration.ofSeconds(8))</code> <em>может быть медленным</em>! Результат <code class="language-plaintext highlighter-rouge">false</code> он всегда возвращает <em>через 8 секунд</em>! Это же убийственно долго для тестов. Постарайтесь не использовать такие проверки.</p> </blockquote> <p><br /></p> <h3 id="force-click">Можно кликать задизейбленные элементы</h3> <p>Начиная с версии 6.15.0, селенид <a href="/2023/05/29/selenide-6.15.0/#clicking-disable-element-fails">не позволяет кликнуть на disabled элемент</a>. Но иногда это бывает надо (например, проверить, что клик по такому элементу ничего не делает). Теперь можно обойти все проверки и тупо кликнуть на какой угодно элемент с помощью параметра <code class="language-plaintext highlighter-rouge">force</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"#disabledButton"</span><span class="o">).</span><span class="na">click</span><span class="o">(</span><span class="n">usingDefaultMethod</span><span class="o">().</span><span class="na">force</span><span class="o">());</span> </code></pre></div></div> <p>Не злоупотребляйте.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2635">issue 2635</a> и <a href="https://github.com/selenide/selenide/pull/2636">PR 2636</a>.</p> <p><br /></p> <h3 id="method-unfocus">Метод <code class="language-plaintext highlighter-rouge">$.unfocus()</code></h3> <p>Мы добавили метод <code class="language-plaintext highlighter-rouge">$.unfocus()</code>, который убирает фокус с элемента.</p> <p>В общем-то это можно было сделать и раньше с помощью <code class="language-plaintext highlighter-rouge">$.pressTab()</code>, но у него могут быть нежелательные сайд-эффекты. Например, другой элемент неожиданно окажется в фокусе. А иногда по нажатию на TAB и вовсе сабмитится форма (например, при вводе OTP-кода).</p> <p>А метод <code class="language-plaintext highlighter-rouge">$.unfocus()</code> в этом смысле безопасен: он просто убирает фокус с элемента. И вы можете проверить, что сработало автозаполнение, форматирование, подсказка и т.п.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"#card-number"</span><span class="o">).</span><span class="na">sendKeys</span><span class="o">(</span><span class="s">"1111-222-33-4444"</span><span class="o">).</span><span class="na">unfocus</span><span class="o">();</span> <span class="err">$</span><span class="o">(</span><span class="s">"#preview"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Pay to 1111-***-**-***4 ?"</span><span class="o">));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2638">issue 2638</a> и <a href="https://github.com/selenide/selenide/pull/2639">PR 2639</a>.</p> <p><br /></p> <h3 id="avoid-page-load-timeout-in-mobile">Исправили page load timeout в мобилках</h3> <p>Был у нас маленький косячок, из-за которого мы случайно выставляли <code class="language-plaintext highlighter-rouge">Configuration.pageLoadTimeout</code> в мобильных тестах. А Appium такую настройку не поддерживает. Из-за чего вы могли видеть такие логи:</p> <blockquote> <p>NotImplementedError: Not implemented yet for pageLoad</p> </blockquote> <p>Некритично, это всего лишь warning. Но больше вы его не увидите.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2612">issue 2612</a> и <a href="https://github.com/selenide/selenide/pull/2628">PR 2628</a>.</p> <p><br /></p> <h3 id="can-add-same-proxy-filter-many-times">Можно добавлять прокси фильтр многократно</h3> <p>Стало чуть проще добавлять свои фильтры для селенидовского прокси. Теперь можно не проверять, что такой фильтр уже был добавлен ранее, а просто добавлять его каждый раз заново:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">RequestFilter</span> <span class="no">REQUEST_LOGGER</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">RequestFilter</span><span class="o">()</span> <span class="o">{...}</span> <span class="nd">@BeforeEach</span> <span class="kd">final</span> <span class="kt">void</span> <span class="nf">setUp</span><span class="o">()</span> <span class="o">{</span> <span class="n">getSelenideProxy</span><span class="o">().</span><span class="na">addRequestFilter</span><span class="o">(</span><span class="s">"request-logger"</span><span class="o">,</span> <span class="no">REQUEST_LOGGER</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>Раньше селенид ругался, что такой фильтр уже есть. А теперь будет спокойненько работать дальше (но только если это реально тот же самый фильтр).</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2617">issue 2617</a> и <a href="https://github.com/selenide/selenide/pull/2630">PR 2630</a>.</p> <p><br /></p> <h3 id="update-dependencies">Обновили зависимости</h3> <ul> <li>bump JUnit from 5.10.1 to 5.10.2</li> <li>bump TestNG from 7.8.0 to 7.9.0</li> <li>Bump slf4jVersion from 2.0.11 to 2.0.12</li> <li>Bump LittleProxy from 2.1.1 to 2.1.2</li> </ul> <p><br /></p> <h3 id="statistics">Статистика</h3> <p>Количество ежемесячных скачиваний Селенида перевалило за 911 тыщ!</p> <center> <img src="/images/2024/01/selenide.downloads.png" width="600px" /> </center> <p>Вау.</p> <p>И ещё один занимательный график.</p> <p>Есть у Селенида один подпроект <a href="https://github.com/selenide/selenide/tree/main/modules/appium"><code class="language-plaintext highlighter-rouge">selenide-appium</code></a> для написания автотестов для мобилок. Раньше он не особо пользовался спросом (по сравнению с самим Селенидом), но в этом году резко попёр вверх.</p> <center> <img src="/images/2024/01/selenide-appium.downloads.png" width="600px" /> </center> <p>Не знаю, чем это объясняется, но это круто. :)</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2024/02/07/selenide-7.1.0/ http://ru.selenide.org/2024/02/07/selenide-7.1.0 2024-02-07T00:00:00+00:00 Вышла Selenide 7.0.1 <p>Вчера мы выпустили <a href="/2023/10/25/selenide-7.0.0/">Selenide 7.0.0</a> и, честно говоря, я ожидал волны жалоб насчёт Java 17.</p> <p>Но нет. На Java 17 никто пока не жаловался. И это здорово! Все обновили джаву, все молодцы. <br /> Но зато люди очень просили обратно циклы по коллекциям.</p> <p>Так и быть, в сегодняшнем <a href="https://github.com/selenide/selenide/milestone/194?closed=1">Selenide 7.0.1</a> мы кое-что вернули:</p> <ul> <li><a href="#restore-collection-loop">Вернули циклы по коллекциям</a></li> <li><a href="#restore-collection-is-empty">Вернули метод <code class="language-plaintext highlighter-rouge">isEmpty()</code> у коллекций</a></li> <li><a href="#restore-self-in-containers">Вернули поле <code class="language-plaintext highlighter-rouge">self</code> в контейнерах</a></li> <li><a href="#rename-collection-condition">Переименовали <code class="language-plaintext highlighter-rouge">CollectionCondition</code> в <code class="language-plaintext highlighter-rouge">WebElementsCondition</code></a></li> <li><a href="#upgrade-to-selenium-4.15.0">UPD 7.0.2: Обновились на Selenium 4.15.0</a></li> </ul> <p><br /></p> <h3 id="restore-collection-loop">Вернули циклы по коллекциям</h3> <p>Теперь вы можете снова использовать <code class="language-plaintext highlighter-rouge">for</code> по коллекциям:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="o">(</span><span class="nc">SelenideElement</span> <span class="n">element</span> <span class="o">:</span> <span class="err">$$</span><span class="o">(</span><span class="s">".element"</span><span class="o">))</span> <span class="o">{</span> <span class="n">element</span><span class="o">.</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">visible</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>А я не устану повторять, что</p> <blockquote> <p>НЕ НАДО ТАК ДЕЛАТЬ!</p> </blockquote> <p><a href="https://github.com/selenide/selenide/wiki/do-not-use-getters-in-tests">Не используйте циклы и условия в тестах!</a></p> <p>Если вы хотите собрать в кучу тексты или атрибуты всех элементов, чтобы потом и проверить, то для этого есть т.н. “collection condition”:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$$</span><span class="o">(</span><span class="s">".errors"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">texts</span><span class="o">(</span><span class="s">"One"</span><span class="o">,</span> <span class="s">"Two"</span><span class="o">,</span> <span class="s">"Three"</span><span class="o">));</span> <span class="err">$$</span><span class="o">(</span><span class="s">"#numbers option"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">attributes</span><span class="o">(</span><span class="s">"value"</span><span class="o">,</span> <span class="s">"one"</span><span class="o">,</span> <span class="s">"two"</span><span class="o">,</span> <span class="s">"three"</span><span class="o">,</span> <span class="s">"four"</span><span class="o">,</span> <span class="s">"five"</span><span class="o">));</span> </code></pre></div></div> <p>А если вы не нашли готовой проверки под ваши нужды, легко можете <a href="https://github.com/selenide/selenide/wiki/Custom-collection-conditions">написать свою</a>. Просто создайте класс от <code class="language-plaintext highlighter-rouge">WebElementsCondition</code> и реализуйте в нём метод <code class="language-plaintext highlighter-rouge">check</code>. Ну изи же. И сможете его переиспользовать в куче своих тестов.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2533">PR 2533</a>.</p> <p><br /></p> <h3 id="restore-collection-is-empty">Вернули метод <code class="language-plaintext highlighter-rouge">isEmpty()</code> у коллекций</h3> <p>Мне по-прежнему непонятно - зачем, но зачем-то люди используют этот метод:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kt">boolean</span> <span class="n">errorsFound</span> <span class="o">=</span> <span class="err">$$</span><span class="o">(</span><span class="s">".error"</span><span class="o">).</span><span class="na">isEmpty</span><span class="o">();</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/pull/2533">PR 2533</a>.</p> <p><br /></p> <h3 id="restore-self-in-containers">Вернули поле <code class="language-plaintext highlighter-rouge">self</code> в контейнерах</h3> <p>В релизе 7.0.0 мы удалили класс <code class="language-plaintext highlighter-rouge">ElementsContainer</code>, а с ним пропал и метод <code class="language-plaintext highlighter-rouge">getSelf()</code>. Я всё ещё нахожу его странным, но почему-то люди его используют.</p> <p>Если это про вас, то вы можете заменить метод <code class="language-plaintext highlighter-rouge">getSelf()</code> на поле с аннотацией <code class="language-plaintext highlighter-rouge">@Self</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">static</span> <span class="kd">class</span> <span class="nc">RadioButton</span> <span class="kd">implements</span> <span class="nc">Container</span> <span class="o">{</span> <span class="nd">@Self</span> <span class="nc">SelenideElement</span> <span class="n">label</span><span class="o">;</span> <span class="nd">@FindBy</span><span class="o">(</span><span class="n">tagName</span> <span class="o">=</span> <span class="s">"input[type=radio]"</span><span class="o">)</span> <span class="nc">SelenideElement</span> <span class="n">input</span><span class="o">;</span> <span class="o">}</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/pull/2534">PR 2534</a>.</p> <p><br /></p> <h3 id="rename-collection-condition">Переименовали <code class="language-plaintext highlighter-rouge">CollectionCondition</code> в <code class="language-plaintext highlighter-rouge">WebElementsCondition</code></h3> <p>Вас это коснётся, только если вы писали <a href="https://github.com/selenide/selenide/wiki/Custom-collection-conditions">самодельные проверки для коллекций</a>.</p> <p>Не беда, просто поменяйте <code class="language-plaintext highlighter-rouge">extends CollectionCondition</code> на <code class="language-plaintext highlighter-rouge">WebElementsCondition</code>.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2372">issue 2372</a> и <a href="https://github.com/selenide/selenide/pull/2533">PR 2533</a>.</p> <p><br /></p> <h3 id="upgrade-to-selenium-4.15.0">UPD 7.0.2: Обновились на Selenium 4.15.0</h3> <p>Позже мы выпустили Selenide 7.0.2 с обновлением на последний Selenium 4.15.0</p> <p>Тут <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">ченджлог селениума</a>.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2540">PR 2540</a>.</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2023/10/26/selenide-7.0.1/ http://ru.selenide.org/2023/10/26/selenide-7.0.1 2023-10-26T00:00:00+00:00 Вышла Selenide 7.0.0 <p>С днём рождения!</p> <p>Да-да, в этот день 12 лет назад был сделан первый коммит в проекте Selenide. Если интересно, здесь <a href="https://www.youtube.com/watch?v=DBkLFL4E5YA&amp;ab_channel=DEVCLUB.EU">видос моего рассказа к 10-летию селенида</a>.</p> <p>К празднику мы выпустили мажорный релиз <a href="https://github.com/selenide/selenide/milestone/191?closed=1">Selenide 7.0.0</a> с обновлением аж сразу на Java 17.</p> <ul> <li><a href="#java17">Обновились на Java 17</a></li> <li><a href="#update-dependencies">Обновили зависимости</a></li> <li><a href="#fix-deadlock-in-static-initialization">Дедлок при инициализации классов</a></li> <li><a href="#report-actual-value-at-the-moment-of-check">Актуальное значение на момент проверки</a></li> <li><a href="#remove-deprecated-condition-methods">Удалили старые методы в <code class="language-plaintext highlighter-rouge">Condition</code></a></li> <li><a href="#remove-deprecated-methods-from-collection-conditions">Удалили старые методы в <code class="language-plaintext highlighter-rouge">CollectionCondition</code></a></li> <li><a href="#remove-deprecated-methods-from-elements-collection">Удалили старые методы в <code class="language-plaintext highlighter-rouge">ElementsCollection</code></a></li> <li><a href="#replace-elements-container-by-container">Заменили <code class="language-plaintext highlighter-rouge">ElementsContainer</code> на <code class="language-plaintext highlighter-rouge">Container</code></a></li> <li><a href="#replace-file-not-found-exception">Заменили <code class="language-plaintext highlighter-rouge">FileNotFoundException</code> на <code class="language-plaintext highlighter-rouge">FileNotDownloadedError</code></a></li> <li><a href="#rename-exceptions-to-errors">Переименовали <code class="language-plaintext highlighter-rouge">*Exception</code> в <code class="language-plaintext highlighter-rouge">*Error</code></a></li> <li><a href="#remove-deprecated-listener">Удалили поддержку устаревшего <code class="language-plaintext highlighter-rouge">WebDriverEventListener</code></a></li> <li><a href="#remove-deprecated-drag-and-drop-methods">Удалили старые методы для Drag’n’drop</a></li> <li><a href="#remove-deprecated-get-selected-value-methods">Удалили устаревшие методы <code class="language-plaintext highlighter-rouge">$.getSelectedValue()</code> и <code class="language-plaintext highlighter-rouge">$.getSelectedText()</code></a></li> <li><a href="#remove-deprecated-testng-annotations">Удалили старые аннотации для TestNG <code class="language-plaintext highlighter-rouge">@Report</code> и <code class="language-plaintext highlighter-rouge">@GlobalTextReport</code></a></li> <li><a href="#remove-other-deprecated-methods">Остальное</a></li> </ul> <p><br /></p> <h3 id="java17">Обновились на Java 17</h3> <p>Чума! Этот день настал!</p> <p>Чтобы использовать Selenide 7.+, вам придётся компилировать и запускать тесты на Java 17+.</p> <p>Как же это круто, да?</p> <p>Я знаю, среди вас найдутся те, кому это решение не понравится. Вы всё ещё вынуждены гонять тесты на Java 8.</p> <p>Но мы не виноваты. Как вы знаете, Selenium 4.14+ перешёл с Java 8 на Java 11. Так что продолжать жить с Java 8 у вас всё равно не получилось бы. Обновиться на Java 11 всё равно пришлось бы. Ну а дальше простое соображение: самое сложное обновление как раз с Java 8 на Java 11. А вот с Java 11 на Java 17 обновиться намного проще. Там и делать-то ничего не надо.</p> <p>Так что обновляйтесь смелее!</p> <blockquote> <p>Жизнь слишком коротка, чтобы продолжать мять титьки с Java 8</p> </blockquote> <p>См. <a href="https://github.com/selenide/selenide/pull/2522">PR 2522</a>.</p> <p><br /></p> <h3 id="update-dependencies">Обновили зависимости</h3> <ul> <li>Обновили Selenium с 4.13.0 на 4.14.1 (<a href="https://github.com/selenide/selenide/pull/2505">PR 2505</a>) <small>- требует Java 11+</small></li> <li>Обновили Appium с 8.6.0 на 9.0.0 (<a href="https://github.com/selenide/selenide/pull/2505">PR 2505</a>) <small>- требует Java 11+</small></li> <li>Обновили TestNG с 7.4.0 на 7.8.0 (<a href="https://github.com/selenide/selenide/pull/2515">PR 2505</a>) <small>- требует Java 11+</small></li> </ul> <p><br /></p> <h3 id="fix-deadlock-in-static-initialization">Исправили дедлок при инициализации классов</h3> <p>Это старая болячка в Selenide: класс <code class="language-plaintext highlighter-rouge">Condition</code> и любой из его дочерних классов зависели друг от друга. Поэтому при определённых обстоятельствах мог случиться дедлок при одновременной загрузке этих классов. Крайне редко, но теоретически возможно.</p> <blockquote> <p>Подробнее про static initialization deadlock можно посмотреть в видосе <a href="https://www.youtube.com/watch?v=2J6iJLYZZUM&amp;t=31m44s">Перформансные войны</a>.</p> </blockquote> <p>При этом нам пришлось переименовать базовый класс для всех проверок из <code class="language-plaintext highlighter-rouge">Condition</code> в <code class="language-plaintext highlighter-rouge">WebElementCondition</code>.</p> <ol> <li>Не пугайтесь, все ваши импорты типа <code class="language-plaintext highlighter-rouge">Condition.visible</code> останутся без изменений.</li> <li>А вот если вы написали свои самодельные проверки, то в них надо будет заменить <code class="language-plaintext highlighter-rouge">extends Condition</code> на <code class="language-plaintext highlighter-rouge">extends WebElementCondition</code>.</li> </ol> <p>См. <a href="https://github.com/selenide/selenide/issues/2372">issue 2372</a> и <a href="https://github.com/selenide/selenide/pull/2453">PR 2453</a>.</p> <p><br /></p> <h3 id="report-actual-value-at-the-moment-of-check">Актуальное значение на момент проверки</h3> <p>Тут идёт речь не о классических проверках веб-элементов, а о <a href="/2021/07/16/selenide-5.23.0/">проверках “нового поколения”</a>: url, localStorage и т.п.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">webdriver</span><span class="o">().</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">url</span><span class="o">(</span><span class="s">"https://some.com/page.html"</span><span class="o">));</span> <span class="n">localStorage</span><span class="o">().</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">item</span><span class="o">(</span><span class="s">"mouse"</span><span class="o">,</span> <span class="s">"Jerry”)); sessionStorage().shouldHave(itemWithValue("</span><span class="n">mouse</span><span class="s">", "</span><span class="nc">Jerry</span><span class="err">”</span><span class="o">));</span> <span class="n">clipboard</span><span class="o">().</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">content</span><span class="o">(</span><span class="s">"Лох, Антилохово, Шалава, Мусорка, Пуково, Попки и Бухалово"</span><span class="o">));</span> </code></pre></div></div> <p>В общем, мы сделали сообщение об ошибке более корректным. За деталями можно сгонять в <a href="https://github.com/selenide/selenide/issues/2500">issue 2500</a> и <a href="https://github.com/selenide/selenide/pull/2501">PR 2501</a>.</p> <p><br /></p> <h3 id="remove-deprecated-condition-methods">Удалили старые методы в <code class="language-plaintext highlighter-rouge">Condition</code></h3> <p>Удалили методы <code class="language-plaintext highlighter-rouge">apply()</code> и <code class="language-plaintext highlighter-rouge">actualValue()</code> в классе <code class="language-plaintext highlighter-rouge">Condition</code>. Они уже давно были помечены как <code class="language-plaintext highlighter-rouge">@Deprecated</code>.</p> <p>Вас это коснётся, только если вы писали свои самодельные проверки. Теперь вместо двух методов <code class="language-plaintext highlighter-rouge">apply()</code> и <code class="language-plaintext highlighter-rouge">actualValue()</code> вам нужно будет реализовывать лишь один метод <code class="language-plaintext highlighter-rouge">check</code>.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2512">PR 2512</a>.</p> <p><br /></p> <h3 id="remove-deprecated-methods-from-collection-conditions">Удалили старые методы в <code class="language-plaintext highlighter-rouge">CollectionCondition</code></h3> <p>Аналогично предыдущему пункту, если у вас есть самодельные проверки для коллекций (<code class="language-plaintext highlighter-rouge">extends CollectionCondition</code>), то в них вместо методов <code class="language-plaintext highlighter-rouge">test</code> и <code class="language-plaintext highlighter-rouge">fail</code> надо будет реализовать один метод <code class="language-plaintext highlighter-rouge">check</code>.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2520">PR 2520</a>.</p> <p><br /></p> <h3 id="remove-deprecated-methods-from-elements-collection">Удалили старые методы в <code class="language-plaintext highlighter-rouge">ElementsCollection</code></h3> <p>Боюсь, тут будет много чего подгорать. :) В общем, теперь <code class="language-plaintext highlighter-rouge">ElementsCollection</code> больше <strong>не наследует</strong> <code class="language-plaintext highlighter-rouge">java.util.List</code>. Изначально это наследование <em>случайно</em> привнесло в <code class="language-plaintext highlighter-rouge">ElementsCollection</code> кучу ненужных методов (таких, как <code class="language-plaintext highlighter-rouge">remove()</code>, <code class="language-plaintext highlighter-rouge">removeRange</code>, <code class="language-plaintext highlighter-rouge">clear</code>, <code class="language-plaintext highlighter-rouge">subList</code> или <code class="language-plaintext highlighter-rouge">listIterator()</code>), которые никогда не планировалось реализовывать. Но пользователи иногда использовали. И даже иногда жаловались на хабре, что они не так работают.</p> <p>Ну вот, теперь нет методов - нет проблем. <br /> В <code class="language-plaintext highlighter-rouge">$$</code> остались только те методы, которые мы считаем нужными. Аминь.</p> <p>P.S. Если у вас есть цикл по элементам коллекции:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">for</span> <span class="o">(</span><span class="nc">SelenideElement</span> <span class="n">el</span> <span class="o">:</span> <span class="err">$$</span><span class="o">(</span><span class="s">"#selenide-users .user"</span><span class="o">))</span> <span class="o">{</span> <span class="n">el</span><span class="o">.</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">visible</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>то он перестанет компилироваться.</p> <p><strong>Быстрое решение</strong> - добавить к нему <code class="language-plaintext highlighter-rouge">asFixedIterable()</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">for</span> <span class="o">(</span><span class="nc">SelenideElement</span> <span class="n">el</span> <span class="o">:</span> <span class="err">$$</span><span class="o">(</span><span class="s">"#selenide-users .user"</span><span class="o">).</span><span class="na">asFixedIterable</span><span class="o">())</span> <span class="o">{</span> <span class="n">el</span><span class="o">.</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">visible</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>Но <strong>правильное решение</strong> - переписать код и избавиться от цикла. Скорее всего вам стоит написать <a href="https://github.com/selenide/selenide/wiki/Custom-collection-conditions">свой collection condition</a>.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2513">PR 2513</a>.</p> <p>UPD <a href="/2023/10/26/selenide-7.0.1/">С версии 7.0.1</a> снова компилируется.</p> <p><br /></p> <h3 id="replace-elements-container-by-container">Заменили <code class="language-plaintext highlighter-rouge">ElementsContainer</code> на <code class="language-plaintext highlighter-rouge">Container</code></h3> <p>Если вы вычленяли куски ваших пэдж обжектов в отдельные переиспользуемые компоненты (или “виджеты”), то они обычно наследовали класс <code class="language-plaintext highlighter-rouge">ElementsContainer</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">WeatherWidget</span> <span class="kd">extends</span> <span class="nc">ElementsContainer</span> <span class="o">{</span> <span class="nd">@FindBy</span><span class="o">(</span><span class="n">id</span> <span class="o">=</span> <span class="s">"air"</span><span class="o">)</span> <span class="kd">private</span> <span class="nc">SelenideElement</span> <span class="n">airTemperature</span><span class="o">;</span> <span class="o">}</span> </code></pre></div></div> <p>Теперь надо будет заменить <code class="language-plaintext highlighter-rouge">ElementsContainer</code> на просто <code class="language-plaintext highlighter-rouge">Container</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">WeatherWidget</span> <span class="kd">implements</span> <span class="nc">Container</span> <span class="o">{</span> <span class="nd">@FindBy</span><span class="o">(</span><span class="n">id</span> <span class="o">=</span> <span class="s">"air"</span><span class="o">)</span> <span class="kd">private</span> <span class="nc">SelenideElement</span> <span class="n">airTemperature</span><span class="o">;</span> <span class="o">}</span> </code></pre></div></div> <p>При этом пропадает метод <code class="language-plaintext highlighter-rouge">getSelf()</code>, который очень давно уже был <code class="language-plaintext highlighter-rouge">@Deprecated</code>. Но если он вам всё ещё нужен, в Selenide 7.0.1 ему изобрели замену в виде аннотации <code class="language-plaintext highlighter-rouge">@Self</code>.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2523">PR 2523</a>.</p> <p><br /></p> <h3 id="replace-file-not-found-exception">Заменили <code class="language-plaintext highlighter-rouge">FileNotFoundException</code> на <code class="language-plaintext highlighter-rouge">FileNotDownloadedError</code></h3> <p>Раньше многие методы типа <code class="language-plaintext highlighter-rouge">$.download()</code> были объявлены как <code class="language-plaintext highlighter-rouge">throws FileNotFoundException</code>. И вам приходилось страдать, добавляя этот бессмысленный <code class="language-plaintext highlighter-rouge">throws FileNotFoundException</code> и в свои тесты. Теперь можно будет подчистить этот хлам и убрать ненужные <code class="language-plaintext highlighter-rouge">catch (FileNotFoundException)</code>, если они у вас были.</p> <p>Теперь методы типа <code class="language-plaintext highlighter-rouge">$.download()</code> будут кидать <code class="language-plaintext highlighter-rouge">FileNotDownloadedError</code>, который является <code class="language-plaintext highlighter-rouge">AssertionError</code>, и его не надо ни объявлять, ни ловить. Если тест не смог скачать файл - тест должен упасть. Никакой дополнительной обработки не требуется.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2526">PR 2526</a>.</p> <p><br /></p> <h3 id="rename-exceptions-to-errors">Переименовали некоторые <code class="language-plaintext highlighter-rouge">*Exception</code> классы в <code class="language-plaintext highlighter-rouge">*Error</code></h3> <p>Лично я не думаю, что это хоть сколько-нибудь важно. <br /> Но религия некоторых пользователей запрещает им называть класс <code class="language-plaintext highlighter-rouge">*Exception</code>, если он не наследует класс <code class="language-plaintext highlighter-rouge">java.lang.Exception</code>.</p> <p>Ну что ж, вы уважаем все религии. Теперь селенидовские классы, наследующие <code class="language-plaintext highlighter-rouge">java.lang.Error</code>, будут называться <code class="language-plaintext highlighter-rouge">*Error</code>.</p> <blockquote> <p>В Украине. Блогерка. Молдова. Беларусь. Таллинн.</p> </blockquote> <p>Нам несложно.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2485">issue 2485</a> и <a href="https://github.com/selenide/selenide/pull/2530">PR 2530</a>.</p> <p><br /></p> <h3 id="remove-deprecated-listener">Удалили поддержку устаревшего <code class="language-plaintext highlighter-rouge">WebDriverEventListener</code></h3> <p>Мы удалили все методы типа <code class="language-plaintext highlighter-rouge">addListener()</code> с параметром типа <code class="language-plaintext highlighter-rouge">org.openqa.selenium.support.events.WebDriverEventListener</code>.</p> <p>Этот класс уже давно был помечен как <code class="language-plaintext highlighter-rouge">@Deprecated</code> в селениуме.</p> <p>Используйте вместо него <code class="language-plaintext highlighter-rouge">addListener()</code> с параметром <code class="language-plaintext highlighter-rouge">org.openqa.selenium.support.events.WebDriverListener</code>.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2516">PR 2516</a>.</p> <p><br /></p> <h3 id="remove-deprecated-drag-and-drop-methods">Удалили старые методы для Drag’n’drop</h3> <p>Очередная чистка. Просто замените</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#what"</span><span class="o">).</span><span class="na">dragAndDropTo</span><span class="o">(</span><span class="n">where</span><span class="o">);</span> </code></pre></div></div> <p>на</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#what"</span><span class="o">).</span><span class="na">dragAndDrop</span><span class="o">(</span><span class="n">to</span><span class="o">(</span><span class="n">where</span><span class="o">));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/pull/2519">PR 2519</a>.</p> <p><br /></p> <h3 id="remove-deprecated-get-selected-value-methods">Удалили устаревшие методы <code class="language-plaintext highlighter-rouge">$.getSelectedValue()</code> и <code class="language-plaintext highlighter-rouge">$.getSelectedText()</code></h3> <p>И ещё чистка.</p> <ol> <li>Замените <code class="language-plaintext highlighter-rouge">$.getSelectedValue()</code> на <code class="language-plaintext highlighter-rouge">$.getSelectedOptionValue()</code></li> <li>Замените <code class="language-plaintext highlighter-rouge">$.getSelectedText()</code> на <code class="language-plaintext highlighter-rouge">$.getSelectedOptionText()</code></li> </ol> <p>См. <a href="https://github.com/selenide/selenide/pull/2521">PR 2521</a>.</p> <p><br /></p> <h3 id="remove-deprecated-testng-annotations">Удалили старые аннотации для TestNG <code class="language-plaintext highlighter-rouge">@Report</code> и <code class="language-plaintext highlighter-rouge">@GlobalTextReport</code></h3> <p>Эти аннотации были не нужны, начиная с <a href="https://selenide.org/2022/08/04/selenide-6.7.0/#cancel-report-testng-annotation">Selenide 6.7.0</a>. Просто удалите их. Да и TestNG удалите, чего уж там. ;)</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2517">PR 2517</a>.</p> <p><br /></p> <h3 id="remove-other-deprecated-methods">Остальное</h3> <ol> <li>Замените <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">new</span> <span class="nc">BearerTokenCredentials</span><span class="o">(</span><span class="s">"pwd"</span><span class="o">)</span> </code></pre></div> </div> <p>на</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">new</span> <span class="nc">BearerTokenCredentials</span><span class="o">(</span><span class="s">"domain"</span><span class="o">,</span> <span class="s">"pwd"</span><span class="o">)</span> </code></pre></div> </div> </li> <li>Замените <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">.</span><span class="na">should</span><span class="o">(</span><span class="n">appears</span><span class="o">);</span> </code></pre></div> </div> <p>на</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">.</span><span class="na">should</span><span class="o">(</span><span class="n">appear</span><span class="o">);</span> <span class="c1">// или просто $.shouldBe(visible)</span> </code></pre></div> </div> </li> <li>Замените <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Selenide</span><span class="o">.</span><span class="na">open</span><span class="o">(</span><span class="n">url</span><span class="o">,</span> <span class="no">BASIC</span><span class="o">,</span> <span class="s">"username"</span><span class="o">,</span> <span class="s">"password"</span><span class="o">);</span> </code></pre></div> </div> <p>на</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Selenide</span><span class="o">.</span><span class="na">open</span><span class="o">(</span><span class="n">url</span><span class="o">,</span> <span class="no">BASIC</span><span class="o">,</span> <span class="k">new</span> <span class="nc">BasicAuthCredentials</span><span class="o">(</span><span class="s">"username"</span><span class="o">,</span> <span class="s">"password"</span><span class="o">));</span> </code></pre></div> </div> </li> </ol> <p>См. <a href="https://github.com/selenide/selenide/pull/2518">PR 2518</a>.</p> <p><br /></p> <p>Навстречу прогрессу!</p> <center> <img src="/images/2023/10/12-Product-Image.webp" width="300" /> </center> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2023/10/25/selenide-7.0.0/ http://ru.selenide.org/2023/10/25/selenide-7.0.0 2023-10-25T00:00:00+00:00 Вышла Selenide 6.19.1 <p>Всем привет!</p> <p>Мир замер в ожидании, грядут большие изменения!<br /> Скоро будет Selenide 7.0.0 с обновлением на Java 11.</p> <blockquote> <p>Эпоха Java8-лямбдовых куколдов проходит</p> </blockquote> <p>А напоследок мы выкатили <strong>последнюю версию</strong>, которая может ещё бегать на Java 8:</p> <p><a href="https://github.com/selenide/selenide/milestone/193?closed=1">Selenide 6.19.1</a></p> <p>В основном там обновления зависимостей, в первую очередь Appium 8.6.0:</p> <ul> <li>bump Appium from 8.5.1 to 8.6.0 <a href="https://github.com/selenide/selenide/pull/2494">(#2494)</a></li> <li>Bump BrowserUpProxy <a href="https://github.com/selenide/selenide/pull/2510">(#2510)</a></li> <li>Bump Netty from 4.1.98.Final to 4.1.100.Final <a href="https://github.com/selenide/selenide/pull/2484">(#2484)</a> <a href="https://github.com/selenide/selenide/pull/2498">(#2498)</a></li> <li>Bump LittleProxy from 2.0.21 to 2.0.22 <a href="https://github.com/selenide/selenide/pull/2491">(#2491)</a></li> <li>Bump Guava from 32.1.2-jre to 32.1.3-jre <a href="https://github.com/selenide/selenide/pull/2499">(#2499)</a></li> <li>Bump Jackson from 2.15.2 to 2.15.3 <a href="https://github.com/selenide/selenide/pull/2502">(#2502)</a> <a href="https://github.com/selenide/selenide/pull/2503">(#2503)</a></li> <li>Bump commons-io from 2.13.0 to 2.14.0 <a href="https://github.com/selenide/selenide/pull/2486">(#2486)</a></li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2023/10/18/selenide-6.19.1/ http://ru.selenide.org/2023/10/18/selenide-6.19.1 2023-10-18T00:00:00+00:00 Вышла Selenide 6.19.0 <p>Всем привет! На излёте сентября вы выкатили <a href="https://github.com/selenide/selenide/milestone/192?closed=1">Selenide 6.19.0</a>.</p> <blockquote> <p>Можешь сплетничать, ненавидеть, регистрировать баги, и обсуждать в чате. Но мы же оба понимаем, что при встрече ты будешь мне мило слать пулреквест.</p> </blockquote> <ul class="blogpost-menu"> <li><a href="#add-highlight-method">Новый метод <code class="language-plaintext highlighter-rouge">$.highlight()</code></a></li> <li><a href="#strip-invisible-spaces-in-collections">Убираем невидимые пробелы в текстах коллекций</a></li> <li><a href="#upgrade-to-selenium-4.13.0">Обновились на Selenium 4.13.0</a></li> <li><a href="#remove-hub-url-check">Убрали строгую проверку на “/wd/hub”</a></li> <li><a href="#replace-elements-container-by-container">Заменили <code class="language-plaintext highlighter-rouge">ElementsContainer</code> на <code class="language-plaintext highlighter-rouge">Container</code></a></li> <li><a href="#tap-double-tap">Методы <code class="language-plaintext highlighter-rouge">$.tap()</code>, <code class="language-plaintext highlighter-rouge">$.doubleTap()</code> для мобилок</a></li> <li><a href="#add-selector-by-class-and-index">Селектор по классу и индексу для мобилок</a></li> <li><a href="#news">Новости</a></li> </ul> <p><br /></p> <h3 id="add-highlight-method">Новый метод <code class="language-plaintext highlighter-rouge">$.highlight()</code> для подсветки элемента</h3> <p>Чувствую, открываем очередной ящик Пандоры, но что поделать.</p> <p>В общем, мы добавили метод для подсветки элемента.</p> <h4 id="зачем-это-надо">Зачем это надо?</h4> <p>Честно говоря, незачем. :)</p> <ul> <li>Когда у вас тесты автоматически бегают на CI, никто на них смотреть не должен, и подсвечивать ничего не нужно.</li> <li>Но вот если надо сделать крутое демо на конференции или просто показать коллегам - тут подсветка может пригодиться. Или, скажем, когда вы дебажите какой-то тест, сложный случай, когда непонятно, что куда кликается.</li> </ul> <h4 id="как-именно-он-подсвечивается">Как именно он подсвечивается?</h4> <p>На данный момент есть два варианта подсветки: цветным фоном (по умолчанию) или рамкой.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">HighlightOptions</span><span class="o">.*;</span> <span class="err">$</span><span class="o">(</span><span class="s">"h1"</span><span class="o">).</span><span class="na">highlight</span><span class="o">();</span> <span class="c1">// по умолчанию - background()</span> <span class="err">$</span><span class="o">(</span><span class="s">"h1"</span><span class="o">).</span><span class="na">highlight</span><span class="o">(</span><span class="n">background</span><span class="o">());</span> <span class="c1">// цветной фон</span> <span class="err">$</span><span class="o">(</span><span class="s">"h1"</span><span class="o">).</span><span class="na">highlight</span><span class="o">(</span><span class="n">border</span><span class="o">());</span> <span class="c1">// цветная рамка</span> </code></pre></div></div> <p>Фону и рамке можно задать свои стили:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"h1"</span><span class="o">).</span><span class="na">highlight</span><span class="o">(</span><span class="n">background</span><span class="o">(</span><span class="s">"rgb(85, 180, 250);"</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">"h1"</span><span class="o">).</span><span class="na">highlight</span><span class="o">(</span><span class="n">border</span><span class="o">(</span><span class="s">"3px solid blue"</span><span class="o">));</span> </code></pre></div></div> <p>А можно и задать полностью крафтовый стиль для выделения элемента:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"h1"</span><span class="o">).</span><span class="na">highlight</span><span class="o">(</span><span class="n">style</span><span class="o">(</span><span class="s">"color: white; background-color: red;"</span><span class="o">));</span> </code></pre></div></div> <p><br /></p> <h4 id="дальнейшее-развитие">Дальнейшее развитие</h4> <p>Пока что метод подсвечивает только тот элемент, который вы скажете. В будущем, наверное, стоит добавить автоматическую подсветку каждого элемента, с которым происходит взаимодействие. Как раз такая подсветка позволит и демо эффектное сделать, и плавающую ошибку подебажить.</p> <p>В общем, делитесь идеями, будем думать.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1277">issue 1277</a>, <a href="https://github.com/selenide/selenide/issues/2395">issue 2395</a> и <a href="https://github.com/selenide/selenide/pull/2481">PR 2481</a>.</p> <p><br /></p> <h3 id="strip-invisible-spaces-in-collections">Убираем невидимые пробелы в текстах коллекций</h3> <p>Как вы помните, в Selenide 6.16.0 мы <a href="/2023/07/02/selenide-6.16.0/#speedup-collection-checks">ускорили работу с коллекциями</a> с помощью вставок JavaScript кода. Оказалось, что при этом мы чуть изменили поведение для элементов, содержащих невидимые пробелы и прочие хитрые символы.</p> <p>Допустим, у нас на страничке есть такой элемент:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"status"</span><span class="nt">&gt;</span> <span class="nt">&lt;span&gt;</span> Боевой дух<span class="nt">&lt;/span&gt;</span> <span class="nt">&lt;span&gt;</span> ипучая<span class="ni">&amp;nbsp;</span>\u200Bдействительность <span class="nt">&lt;/span&gt;</span> <span class="nt">&lt;/div&gt;</span> </code></pre></div></div> <p>И раньше проверка типа</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$$</span><span class="o">(</span><span class="s">"#status span"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">texts</span><span class="o">(</span><span class="s">"Боевой дух"</span><span class="o">,</span> <span class="s">"ипучая действительность"</span><span class="o">));</span> </code></pre></div></div> <p>падала:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Expected</span> <span class="o">:[</span><span class="nc">Боевой</span> <span class="n">дух</span><span class="o">,</span> <span class="n">ипучая</span> <span class="n">действительность</span><span class="o">]</span> <span class="nc">Actual</span> <span class="o">:[</span><span class="nc">Боевой</span> <span class="n">дух</span><span class="o">,</span> <span class="n">ипучая</span> <span class="n">действительность</span><span class="o">]</span> </code></pre></div></div> <p>Причём выглядит сообщение так, как будто тексты одинаковые. Но в первой строке - обычный пробел, а во второй - невидимый пробел “<code class="language-plaintext highlighter-rouge">​</code>”.</p> <p>Теперь же селенид будет вычищать такие невидимые пробелы. Правильно это или нет, можно спорить, но так велит нам стандарт WebDriver, и так работает Selenium. И мы тоже будем соответствовать.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2469">issue 2469</a> и <a href="https://github.com/selenide/selenide/pull/2482">PR 2482</a>.<br /> Спасибо <a href="https://github.com/Au6ojlut">Maksim Au6ojlut</a> за <a href="https://github.com/selenide/selenide/issues/2469#issuecomment-1721584046">подсказку с чёртовыми пробелами</a>.</p> <p><br /></p> <h3 id="upgrade-to-selenium-4.13.0">Обновились на Selenium 4.13.0</h3> <p>Обновили Selenium с 4.12.1 на 4.13.0<br /> Вот тут его <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">ченджлог</a>.</p> <p>Несколько важных багфиксов, но всё ещё бегает на Java8. Ловите, пока он не стал требовать Java 11+! ;)</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2479">PR 2479</a>.</p> <p><br /></p> <h3 id="remove-hub-url-check">Убрали строгую проверку на “/wd/hub”</h3> <p>Если вы используете Selenoid, то раньше плагин <code class="language-plaintext highlighter-rouge">selenide-selenoid</code> проверял, чтобы URL заканчивался строкой <code class="language-plaintext highlighter-rouge">/wd/hub</code>. Оказалось, что URL бывает и другим, и поэтому мы эту проверку убрали.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2475">issue 2475</a>.<br /> Спасибо <a href="https://github.com/Plodick">Dmitry Plodukhin</a> за <a href="https://github.com/selenide/selenide/pull/2476">PR 2476</a>.</p> <p><br /></p> <h3 id="replace-elements-container-by-container">Заменили класс <code class="language-plaintext highlighter-rouge">ElementsContainer</code> на интерфейс <code class="language-plaintext highlighter-rouge">Container</code></h3> <p>Как вы помните, недавно мы <a href="/2023/09/06/selenide-6.18.0/#no-elements-container-for-page-object">запретили пэдж обжектам</a> наследоваться от <code class="language-plaintext highlighter-rouge">ElementsContainer</code>.</p> <p>Такой вариант больше не работает:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">LoginPage</span> <span class="kd">extends</span> <span class="nc">ElementsContainer</span> <span class="o">{</span> <span class="o">}</span> </code></pre></div></div> <p>Я по-прежнему настаиваю, что это не нужно, но нашлись такие проекты, где это необходимо из-за текущего наследия и невозможности всё переписать. Для таких проектов мы добавили интерфейс <code class="language-plaintext highlighter-rouge">Container</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">LoginPage</span> <span class="kd">implements</span> <span class="nc">Container</span> <span class="o">{</span> <span class="o">}</span> </code></pre></div></div> <p>Для обычных виджетов тоже рекомендуется поменять <code class="language-plaintext highlighter-rouge">extends ElementsContainer</code> на <code class="language-plaintext highlighter-rouge">implements Container</code>.</p> <p>Разница только в том, что это интерфейс, а не абстрактный класс (надо писать “implements” вместо “extends”), и в нём не будет метода <code class="language-plaintext highlighter-rouge">getSelf()</code>. Ну и не надо.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2439">issue 2439</a> и <a href="https://github.com/selenide/selenide/pull/2465">PR 2465</a>.</p> <p><br /></p> <h3 id="tap-double-tap">Добавили методы <code class="language-plaintext highlighter-rouge">$.tap()</code>, <code class="language-plaintext highlighter-rouge">$.doubleTap()</code> для мобилок</h3> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">SelenideAppium</span><span class="o">.</span><span class="err">$</span><span class="o">;</span> <span class="err">$</span><span class="o">(</span><span class="nc">By</span><span class="o">.</span><span class="na">name</span><span class="o">(</span><span class="s">"ComputeSumButton"</span><span class="o">)).</span><span class="na">tap</span><span class="o">();</span> <span class="err">$</span><span class="o">(</span><span class="nc">AppiumBy</span><span class="o">.</span><span class="na">xpath</span><span class="o">(</span><span class="s">"//android.widget.Button"</span><span class="o">)).</span><span class="na">doubleTap</span><span class="o">();</span> <span class="err">$</span><span class="o">(</span><span class="nc">AppiumBy</span><span class="o">.</span><span class="na">xpath</span><span class="o">(</span><span class="s">".//*[@text='Лютая арта']"</span><span class="o">)).</span><span class="na">tap</span><span class="o">(</span><span class="n">longPressFor</span><span class="o">(</span><span class="n">ofSeconds</span><span class="o">(</span><span class="mi">4</span><span class="o">)));</span> </code></pre></div></div> <p>Спасибо <a href="https://github.com/qwez">qwez</a> за <a href="https://github.com/selenide/selenide/pull/2467">PR 2467</a>.</p> <p><br /></p> <h3 id="add-selector-by-class-and-index">Добавили селектор по классу и индексу для мобилок</h3> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">AppiumSelectors</span><span class="o">.</span><span class="na">byClassNameAndIndex</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">SelenideAppium</span><span class="o">.</span><span class="err">$</span><span class="o">;</span> <span class="err">$</span><span class="o">(</span><span class="n">byClassNameAndIndex</span><span class="o">(</span><span class="s">"android.widget.TextView"</span><span class="o">,</span> <span class="mi">7</span><span class="o">)).</span><span class="na">tap</span><span class="o">();</span> </code></pre></div></div> <p>Спасибо <a href="https://github.com/amuthansakthivel">Amuthan Sakthivel</a> за <a href="https://github.com/selenide/selenide/pull/2440">PR 2440</a>.</p> <p><br /></p> <h3 id="news">Новости</h3> <ul> <li><a href="https://github.com/titusfortner/selenium-logger">Selenium logger</a> - новый проект от Titus Fortner</li> <li><a href="https://www.baeldung.com/selenide">Introduction to Selenide</a> - Исторический момент! Пост на легендарном сайте Baeldung.</li> <li><a href="https://www.youtube.com/watch?v=C8rbEuvvg0I&amp;ab_channel=LambdaTest">Selenide appium</a> - Видос с последней конференции LambdaTest от Amuthan Sakthivel</li> <li><a href="https://intexsoft.com/blog/selenide-test-automation-using-selenoid-in-the-docker-container/">Selenide test automation: using Selenoid in docker</a> by Dora &amp; Margarita</li> <li><a href="https://zenn.dev/ragnar1904/articles/selenide-essentials">Things to keep in mind when using Selenide</a> - пост на японском от nilwurtz</li> <li><a href="https://updates4devs.com/intro-to-selenidebaeldung/?feed_id=28562">Intro to Selenide</a> By Updates4Devs.com</li> <li><a href="https://www.youtube.com/watch?v=FZA5PGxPzR0&amp;t=156s&amp;ab_channel=QAGURU">Non-static Selenide: пробуем жить с selenide-core и что это нам даст</a> - интересная нетривиальная тема от Дмитрий Тучс</li> <li><a href="https://www.linkedin.com/pulse/%2525D0%2525BF%2525D0%2525BE%2525D1%252587%2525D0%2525B5%2525D0%2525BC%2525D1%252583-%2525D0%2525BD%2525D0%2525B0%2525D1%252581%2525D0%2525BB%2525D0%2525B5%2525D0%2525B4%2525D0%2525BE%2525D0%2525B2%2525D0%2525B0%2525D0%2525BD%2525D0%2525B8%2525D0%2525B5-%2525D0%2525B2-%2525D0%2525B0%2525D0%2525B2%2525D1%252582%2525D0%2525BE%2525D1%252582%2525D0%2525B5%2525D1%252581%2525D1%252582%2525D0%2525B0%2525D1%252585-%2525D1%25258D%2525D1%252582%2525D0%2525BE-%2525D0%2525B0%2525D0%2525BD%2525D1%252582%2525D0%2525B8%2525D0%2525BF%2525D0%2525B0%2525D1%252582%2525D1%252582%2525D0%2525B5%2525D1%252580%2525D0%2525BD-ruslan-galliamov%3FtrackingId=klEJOeEYQ2K2mix0G2%252F9mQ%253D%253D/?trackingId=klEJOeEYQ2K2mix0G2%2F9mQ%3D%3D">Почему наследование в автотестах это антипаттерн?</a> - пост (не про Selenide) от Ruslan Galliamov</li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2023/09/28/selenide-6.19.0/ http://ru.selenide.org/2023/09/28/selenide-6.19.0 2023-09-28T00:00:00+00:00 Вышла Selenide 6.18.0 <p>Все уже перевернули календарь?<br /> Тогда при свете костров рябин можете обновиться на <a href="https://github.com/selenide/selenide/milestone/190?closed=1">Selenide 6.18.0</a>.</p> <ul class="blogpost-menu"> <li><a href="#show-actual-texts-in-collections">Показываем актуальные тексты в коллекциях</a></li> <li><a href="#update-to-selenium-4.12.1">Обновили Selenium с 4.11.0 на 4.12.1</a></li> <li><a href="#restore-basic-auth-via-cdp">Вернули BasicAuth через DevTools</a></li> <li><a href="#add-method-get-options">Добавили метод <code class="language-plaintext highlighter-rouge">$$.getOptions()</code></a></li> <li><a href="#get-focused-element-lazy-loaded">Метод <code class="language-plaintext highlighter-rouge">getFocusedElement()</code> обленился</a></li> <li><a href="#support-appium-elements-in-page-objects">Поля <code class="language-plaintext highlighter-rouge">SelenideAppiumElement</code> в пэдж обжектах</a></li> <li><a href="#exact-scroll-in-appium">Точечный скроллинг в мобилках</a></li> <li><a href="#no-elements-container-for-page-object">Не наследовать пэдж обжект от <code class="language-plaintext highlighter-rouge">ElementsContainer</code></a></li> <li><a href="#update-dependencies">Обновили зависимости</a></li> <li><a href="#statistics">Статистика</a></li> </ul> <p><br /></p> <h3 id="show-actual-texts-in-collections">Показываем актуальные тексты в коллекциях</h3> <p>В релизе 6.16.0 мы <a href="/2023/07/02/selenide-6.16.0/#speedup-collection-checks">ускорили проверки коллекций</a>.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$$</span><span class="o">(</span><span class="s">".troubles"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">texts</span><span class="o">(</span> <span class="s">"Всё не то"</span><span class="o">,</span> <span class="s">"всё не так"</span><span class="o">,</span> <span class="s">"ты мой друг"</span><span class="o">,</span> <span class="s">"я твой враг"</span><span class="o">));</span> </code></pre></div></div> <p>Одна из оптимизаций была такая: если размер коллекции не совпадает, то селенид даже не начинает проверять тексты элементов, а сразу кидает ошибку:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">List</span> <span class="n">size</span> <span class="nl">mismatch:</span> <span class="nl">expected:</span> <span class="o">=</span> <span class="mi">4</span><span class="o">,</span> <span class="nl">actual:</span> <span class="mi">3</span> </code></pre></div></div> <p>Но люди стали жаловаться, что хотелось бы увидеть, какие же там всё-таки были тексты. Похоже, это тот случай, когда удобство важнее скорости. А падают ваши тесты не так уж часто, ведь правда? ;)</p> <p>Поэтому с этого релиза будем показывать и размер, и тексты:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">List</span> <span class="n">size</span> <span class="nf">mismatch</span> <span class="o">(</span><span class="nl">expected:</span> <span class="mi">4</span><span class="o">,</span> <span class="nl">actual:</span> <span class="mi">3</span><span class="o">)</span> <span class="nc">Actual</span> <span class="o">(</span><span class="mi">3</span><span class="o">):</span> <span class="o">[</span><span class="nc">Журавлей</span> <span class="n">белый</span> <span class="n">клин</span><span class="o">,</span> <span class="n">твоя</span> <span class="n">дочь</span><span class="o">,</span> <span class="n">и</span> <span class="n">мой</span> <span class="n">сын</span><span class="o">]</span> <span class="nc">Expected</span> <span class="o">(</span><span class="mi">4</span><span class="o">):</span> <span class="o">[</span><span class="nc">Всё</span> <span class="n">не</span> <span class="n">то</span><span class="o">,</span> <span class="n">всё</span> <span class="n">не</span> <span class="n">так</span><span class="o">,</span> <span class="n">ты</span> <span class="n">мой</span> <span class="n">друг</span><span class="o">,</span> <span class="n">я</span> <span class="n">твой</span> <span class="n">враг</span><span class="o">]</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2434">issue 2434</a> и <a href="https://github.com/selenide/selenide/pull/2456">PR 2456</a>.</p> <p><br /></p> <h3 id="update-to-selenium-4.12.1">Обновили Selenium с 4.11.0 на 4.12.1</h3> <p>Ченджлог <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">здесь</a>. Среди прочего, там исправили злополучный <a href="https://github.com/SeleniumHQ/selenium/issues/12576">дедлок в devtools</a>, из-за которого нам пришлось выпустить предыдущий релиз.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2452">PR 2452</a>.</p> <p><br /></p> <h3 id="restore-basic-auth-via-cdp">Вернули BasicAuth через DevTools</h3> <p>В релизе 6.16.0 мы запилили <a href="/2023/07/02/selenide-6.16.0/#improve-basic-auth-in-chromium-browsers">авторизацию BasicAuth через механизм <code class="language-plaintext highlighter-rouge">HasAuthentication</code> в браузерах семейства Chromium</a>.</p> <p>Потом нам пришлось её откатить из-за вышеупомянутого дедлока в вебдрайвере. Теперь селениум обновили, дедлок исправили, и мы вернули авторизацию взад.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2336">issue 2336</a>, <a href="https://github.com/selenide/selenide/pull/2358">PR 2358</a> и <a href="https://github.com/selenide/selenide/pull/2452">PR 2452</a>.</p> <p><br /></p> <h3 id="add-method-get-options">Добавили метод <code class="language-plaintext highlighter-rouge">$$.getOptions()</code></h3> <p>В селениде уже был метод <code class="language-plaintext highlighter-rouge">$$.getSelectedOptions()</code> - он возвращает <em>выбранные</em> опции элемента <code class="language-plaintext highlighter-rouge">&lt;select&gt;</code>. А теперь мы добавили похожий метод <code class="language-plaintext highlighter-rouge">$$.getOptions()</code>, чтобы можно было проверить <em>все</em> его опции.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"select"</span><span class="o">).</span><span class="na">getOptions</span><span class="o">()</span> <span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">texts</span><span class="o">(</span><span class="s">"день прощанья"</span><span class="o">,</span> <span class="s">"костры рябин"</span><span class="o">,</span> <span class="s">"обещания"</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">"select"</span><span class="o">).</span><span class="na">selectOption</span><span class="o">(</span><span class="s">"день прощанья"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"select"</span><span class="o">).</span><span class="na">getSelectedOptions</span><span class="o">()</span> <span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">texts</span><span class="o">(</span><span class="s">"день прощанья"</span><span class="o">));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2445">issue 2445</a> и <a href="https://github.com/selenide/selenide/pull/2446">PR 2446</a>.</p> <p><br /></p> <h3 id="get-focused-element-lazy-loaded">Метод <code class="language-plaintext highlighter-rouge">getFocusedElement()</code> обленился</h3> <p>Теперь метод <code class="language-plaintext highlighter-rouge">getFocusedElement()</code> возвращает <code class="language-plaintext highlighter-rouge">SelenideElement</code>, а не <code class="language-plaintext highlighter-rouge">WebElement</code>.</p> <p>Что автоматически означает ленивую загрузку и прочие плюшки.<br /> А ещё вы можете использовать для него стандартные should-проверки:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Selenide</span><span class="o">.</span><span class="na">getFocusedElement</span><span class="o">()</span> <span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">tagName</span><span class="o">(</span><span class="s">"input"</span><span class="o">),</span> <span class="n">id</span><span class="o">(</span><span class="s">"otpCode"</span><span class="o">));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/pull/2454">PR 2454</a>.</p> <p><br /></p> <h3 id="support-appium-elements-in-page-objects">Добавили поддержку полей <code class="language-plaintext highlighter-rouge">SelenideAppiumElement</code> в пэдж обжектах</h3> <p>Если вы пишете тесты для мобилок с нашим плагином <code class="language-plaintext highlighter-rouge">selenide-appium</code>, то теперь вы можете объявлять поля пэдж обжекта с типом <code class="language-plaintext highlighter-rouge">SelenideAppiumElement</code>, вместо <code class="language-plaintext highlighter-rouge">SelenideElement</code>.</p> <p>Это даёт дополнительные методы для мобилок: <code class="language-plaintext highlighter-rouge">hideKeyboard()</code>, <code class="language-plaintext highlighter-rouge">swipe()</code> и т.п.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">LoginPage</span> <span class="o">{</span> <span class="nd">@AndroidFindBy</span><span class="o">(</span><span class="n">accessibility</span> <span class="o">=</span> <span class="s">"Username input field"</span><span class="o">)</span> <span class="nc">SelenideAppiumElement</span> <span class="n">login</span><span class="o">;</span> <span class="nd">@AndroidFindBy</span><span class="o">(</span><span class="n">accessibility</span> <span class="o">=</span> <span class="s">"Password input field"</span><span class="o">)</span> <span class="nc">SelenideElement</span> <span class="n">password</span><span class="o">;</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">login</span><span class="o">()</span> <span class="o">{</span> <span class="n">password</span><span class="o">.</span><span class="na">swipeTo</span><span class="o">();</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2437">issue 2437</a> и <a href="https://github.com/selenide/selenide/pull/2438">PR 2438</a>.</p> <p><br /></p> <h3 id="exact-scroll-in-appium">Точечный скроллинг в мобилках</h3> <p>Продолжая тему мобилок. В плагине <code class="language-plaintext highlighter-rouge">selenide-appium</code> есть метод <code class="language-plaintext highlighter-rouge">scroll</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">AppiumScrollOptions</span><span class="o">.</span><span class="na">with</span><span class="o">;</span> <span class="err">$</span><span class="o">.</span><span class="na">scroll</span><span class="o">(</span><span class="n">with</span><span class="o">(</span><span class="no">UP</span><span class="o">,</span> <span class="mi">20</span><span class="o">));</span> <span class="c1">// свайпать вверх, не больше 20 раз</span> </code></pre></div></div> <p>А теперь ему в параметрах можно более точно указать начальную и конечную точку свайпа (в процентах от высоты экрана):</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">AppiumScrollOptions</span><span class="o">.</span><span class="na">up</span><span class="o">;</span> <span class="err">$</span><span class="o">.</span><span class="na">scroll</span><span class="o">(</span><span class="n">up</span><span class="o">(</span><span class="mi">10</span><span class="o">,</span> <span class="mi">80</span><span class="o">));</span> <span class="c1">// свайпать от точки 10% до точки 80%</span> </code></pre></div></div> <p>Спасибо <a href="https://github.com/qwez">qwez</a> за <a href="https://github.com/selenide/selenide/pull/2449">PR 2449</a>.</p> <p><br /></p> <h3 id="no-elements-container-for-page-object">Нельзя наследовать пэдж обжект от <code class="language-plaintext highlighter-rouge">ElementsContainer</code></h3> <p>Некоторые пользователи жаловались на такой вот странный ворнинг от селенида:</p> <blockquote> <p>WARN com.codeborne.selenide.impl.SelenidePageFactory - Cannot initialize field private com.codeborne.selenide.SelenideElement com.codeborne.selenide.ElementsContainer.self</p> </blockquote> <p>Мы начали исследовать тему и поняли, что это происходит, если вы наследуете пэдж обжект от <code class="language-plaintext highlighter-rouge">ElementsContainer</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">LoginPage</span> <span class="kd">extends</span> <span class="nc">ElementsContainer</span> <span class="o">{</span> <span class="o">}</span> </code></pre></div></div> <p>Что на самом деле <strong>не нужно</strong>. Собственно, теперь и не получится. :)</p> <p>Изначально <code class="language-plaintext highlighter-rouge">ElementsContainer</code> был задуман для того, чтобы объявлять компоненты <em>внутри</em> пэдж обжекта:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">LoginPage</span> <span class="o">{</span> <span class="nd">@FindBy</span><span class="o">(</span><span class="n">id</span><span class="o">=</span><span class="s">"weather"</span><span class="o">)</span> <span class="nc">WeatherWidget</span> <span class="n">weatherWidget</span><span class="o">;</span> <span class="o">}</span> <span class="kd">class</span> <span class="nc">WeatherWidget</span> <span class="kd">extends</span> <span class="nc">ElementsContainer</span> <span class="o">{</span> <span class="nd">@FindBy</span><span class="o">(</span><span class="n">id</span><span class="o">=</span><span class="s">"temperature"</span><span class="o">)</span> <span class="nc">SelenideElement</span> <span class="n">temperature</span><span class="o">;</span> <span class="o">}</span> </code></pre></div></div> <p>Просто уберите <code class="language-plaintext highlighter-rouge">extends ElementsContainer</code> из своего пэдж обжекта, и всё будет прекрасно работать.</p> <p>P.S. Дело в том, что это разные объекты с разной судьбой.</p> <ol> <li>Пэдж обжекты вы можете создавать методом <code class="language-plaintext highlighter-rouge">LoginPage page = Selenide.page();</code>. И для этого им <em>не требуется</em> наследоваться от <code class="language-plaintext highlighter-rouge">ElementsContainer</code>.</li> <li>А вот поля этих пэдж обжектов надо наследовать от <code class="language-plaintext highlighter-rouge">ElementsContainer</code>, чтобы селенид знал, что в них надо тоже искать аннотации <code class="language-plaintext highlighter-rouge">@FindBy</code>.</li> </ol> <p>См. <a href="https://github.com/selenide/selenide/issues/2439">issue 2439</a> и <a href="https://github.com/selenide/selenide/pull/2455">PR 2455</a>.</p> <p><br /></p> <h3 id="update-dependencies">Обновили зависимости</h3> <ul> <li>bump LittleProxy from 2.0.19 to 2.0.20 (fixes a memory leak in Selenide proxy)</li> <li>update vulnerable jackson dependency - см. <a href="https://github.com/selenide/selenide/pull/2442">PR 2442</a></li> </ul> <p><br /></p> <h3 id="statistics">Статистика</h3> <p>Количество ежемесячных скачиваний Селенида перевалило за 670 тыщ!</p> <center> <img src="/images/2023/09/selenide.downloads.png" width="800" /> </center> <p><br /> Такими темпами у нас будет всё всерьёз. Следующего второго сентября.</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2023/09/06/selenide-6.18.0/ http://ru.selenide.org/2023/09/06/selenide-6.18.0 2023-09-06T00:00:00+00:00 Вышла Selenide 6.17.2 <p>Добрий вечір!</p> <p>Сегодня 24 августа - День Независимости Украины.<br /> И в честь этого праздника - маленький релизец <a href="https://github.com/selenide/selenide/milestone/189?closed=1">Selenide 6.17.2</a>.</p> <p><br /></p> <h3 id="отвисли-зависающий-вебдрайвер-ещё-раз">Отвисли зависающий вебдрайвер ещё раз</h3> <p><a href="/2023/08/20/selenide-6.17.1/">В прошлом релизе</a> мы исправили проблему с зависающим вебдрайвером <em>для большинства пользователей</em>.<br /> Но остались несчастные, которые вынуждены открывать тестируемые сайты в Хроме через BasicAuth. И вот для них вебдрайвер по-прежнему зависал.</p> <blockquote> <p>Усилия по установлению потерянной с вебдрайвером связи<br /> не дали результатов.<br /> По предварительным данным, поток “CDP Connection” перешёл на нерасчётную орбиту и остановился, столкнувшись с зашаренным локом.<br /> Стактрейсы зависших потоков не поддаются визуальному опознанию.</p> </blockquote> <p>Что делать - пришлось пока откатить <a href="https://github.com/selenide/selenide/pull/2358">CDP-based authentication</a> до лучших времён, пока не исправится соответствующая <a href="https://github.com/SeleniumHQ/selenium/issues/12576">бага в вебдрайвере</a>.</p> <h3 id="как-повторить-проблему">Как повторить проблему</h3> <p>Если интересно, как проявляется проблема - запустите этот тест:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">public</span> <span class="kd">class</span> <span class="nc">BasicAuthTest</span> <span class="o">{</span> <span class="nd">@RepeatedTest</span><span class="o">(</span><span class="mi">2</span><span class="o">)</span> <span class="kt">void</span> <span class="n">вот_этот_кусок_зависает_на_второй_попытке</span><span class="o">()</span> <span class="o">{</span> <span class="n">open</span><span class="o">(</span><span class="s">"https://the-internet.herokuapp.com/basic_auth"</span><span class="o">,</span> <span class="no">BASIC</span><span class="o">,</span> <span class="k">new</span> <span class="nf">BasicAuthCredentials</span><span class="o">(</span><span class="s">"the-internet.herokuapp.com"</span><span class="o">,</span> <span class="s">"admin"</span><span class="o">,</span> <span class="s">"admin"</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">"#content"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Congratulations!"</span><span class="o">));</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div></div> <p>Первый прогон срабатывает, второй - зависает. На Selenide 6.17.1.</p> <p>А на Selenide 6.17.2 больше не зависает. Ура.</p> <p><br /></p> <center> <img src="/images/2023/08/happy-independence-day-ukraine-vector-21712783.jpg" width="300" /> </center> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2023/08/24/selenide-6.17.2/ http://ru.selenide.org/2023/08/24/selenide-6.17.2 2023-08-24T00:00:00+00:00 Вышла Selenide 6.17.1 <p>Доброе утро!</p> <p>Сегодня 20 августа - <a href="https://www.visitestonia.com/ru/%D0%BF%D0%BE%D1%87%D0%B5%D0%BC%D1%83-%D1%8D%D1%81%D1%82%D0%BE%D0%BD%D0%B8%D1%8F/%D0%B4%D0%B5%D0%BD%D1%8C-%D0%B2%D0%BE%D1%81%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F-%D1%8D%D1%81%D1%82%D0%BE%D0%BD%D1%81%D0%BA%D0%BE%D0%B9-%D1%80%D0%B5%D1%81%D0%BF%D1%83%D0%B1%D0%BB%D0%B8%D0%BA%D0%B8">День Восстановления Независимости Эстонии</a>.</p> <p>В честь этого праздника - небольшой релиз <a href="https://github.com/selenide/selenide/milestone/188?closed=1">Selenide 6.17.1</a>!</p> <ul> <li><a href="#fix-hanging-webdriver">Отвисли зависающий вебдрайвер</a></li> <li><a href="#support-type-in-mobile-apps">Добавили поддержку <code class="language-plaintext highlighter-rouge">$.type()</code> в мобилках</a></li> <li><a href="#fix-type-with-keys">Исправили метод <code class="language-plaintext highlighter-rouge">$.type(Keys.*)</code></a></li> <li><a href="#remove-spaces-from-texts">Убрали пробелы с концов в <code class="language-plaintext highlighter-rouge">$$.texts()</code></a> <p><br /></p> </li> </ul> <h3 id="fix-hanging-webdriver">Отвисли зависающий вебдрайвер</h3> <p>В релизе Selenide 6.16.0 (на самом деле <a href="https://github.com/selenide/selenide/pull/2358">PR 2358</a>), в селениде случайно появилась бага, из-за которой вебдрайвер мог легко зависнуть. А именно, если вызвать два раза подряд <code class="language-plaintext highlighter-rouge">open(url, pageClass)</code>, то вебдрайвер накрепко зависает.</p> <blockquote> <p>По предварительным данным, вебдрайвер перешел на нерасчётную орбиту и разбился, столкнувшись с дедлоком в параллельных потоках devtools.</p> </blockquote> <p>Вот такие ничоси. :)</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nd">@Test</span> <span class="kd">public</span> <span class="kt">void</span> <span class="n">вот_этот_кусок_зависает</span><span class="o">()</span> <span class="o">{</span> <span class="nc">Selenide</span><span class="o">.</span><span class="na">open</span><span class="o">(</span><span class="s">"https://www.google.com/"</span><span class="o">,</span> <span class="nc">GooglePage</span><span class="o">.</span><span class="na">class</span><span class="o">);</span> <span class="nc">Selenide</span><span class="o">.</span><span class="na">open</span><span class="o">(</span><span class="s">"https://www.google.com/"</span><span class="o">,</span> <span class="nc">GooglePage</span><span class="o">.</span><span class="na">class</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>На самом деле это оказалась <a href="https://github.com/SeleniumHQ/selenium/issues/12576">бага в вебдрайвере</a>, она <a href="https://github.com/asolntsev/selenium-deadlock">легко повторяется</a> и с чистым селениумом. А изменения в Selenide 6.16.0 просто сделали её повторение более вероятным.</p> <p>В общем, проблему мы исправили для большинства пользователей. Но не для всех (грубо говоря, селенид просто старается не вызывать опасный код, пока для этого нет явной необходимости).<br /> А полного исправления придётся ждать на стороне ведрайвера.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2424">issue 2424</a> и <a href="https://github.com/selenide/selenide/pull/2428">PR 2428</a>.</p> <blockquote> <p>Огромное спасибо <a href="https://github.com/extryd">extryd</a> за чёткое описание проблемы с ультрапростыми инструкциями, как её стабильно повторить. Такое описание бага - неоценимая помощь мейнтейнерам. Все бы тикеты такие были!</p> </blockquote> <p><br /></p> <h3 id="support-type-in-mobile-apps">Добавили поддержку <code class="language-plaintext highlighter-rouge">$.type()</code> в мобилках</h3> <p>В предыдущем релизе появился метод</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">.</span><span class="na">type</span><span class="o">(</span><span class="s">"Биомеханоиды и трансгендеры"</span><span class="o">);</span> </code></pre></div></div> <p>который вбивает текст медленно, с задержками. Полезно для тестирования автозаполнения, поиска и т.п.</p> <p>Но оказалось, что он не работал в мобилках (<a href="https://github.com/selenide/selenide/tree/main/modules/appium">selenide-appium</a>). Теперь будет работать.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2191#issuecomment-1667578383">issue</a> и <a href="https://github.com/selenide/selenide/pull/2408">PR 2408</a>.</p> <p><br /></p> <h3 id="fix-type-with-keys">Исправили метод <code class="language-plaintext highlighter-rouge">$.type(Keys.*)</code></h3> <p>Вышеупомянутый метод <code class="language-plaintext highlighter-rouge">type</code> принимает не только строки, но и <code class="language-plaintext highlighter-rouge">CharSequence</code>. Что означает, что такой вариант тоже должен работать:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kn">import</span> <span class="nn">org.openqa.selenium.Keys</span><span class="o">;</span> <span class="err">$</span><span class="o">(</span><span class="s">"input"</span><span class="o">).</span><span class="na">type</span><span class="o">(</span><span class="nc">Keys</span><span class="o">.</span><span class="na">ENTER</span><span class="o">);</span> </code></pre></div></div> <p>Вот только он ломался, потому что пытался закастить <code class="language-plaintext highlighter-rouge">Keys.ENTER</code> (который вообще-то <code class="language-plaintext highlighter-rouge">CharSequence</code>) к типу <code class="language-plaintext highlighter-rouge">String</code>. В общем, теперь этот вариант тоже будет работать (хотя польза от него неясна).</p> <p>Спасибо <a href="https://github.com/bereg2k">Oleg Berezhnoy</a> за наблюдательность и <a href="https://github.com/selenide/selenide/issues/2422">issue 2422</a>.<br /> Фикс в <a href="https://github.com/selenide/selenide/pull/2421">PR 2421</a>.</p> <p><br /></p> <h3 id="remove-spaces-from-texts">Убрали пробелы с концов в <code class="language-plaintext highlighter-rouge">$$.texts()</code></h3> <p>В Selenide 6.16.0 мы <a href="/2023/07/02/selenide-6.16.0/#speedup-collection-checks">ускорили работу с коллекциями</a> с помощью вставок JavaScript кода. <br /> Но вечновнимательный <a href="https://github.com/bereg2k">Oleg Berezhnoy</a> заметил, что при этом мы случайно поменяли поведение метода <code class="language-plaintext highlighter-rouge">$$.texts()</code>. Раньше он возвращал список текстов элементов, в которых пробелы в начале и конце обрезаны:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">assertThat</span><span class="o">(</span><span class="err">$$</span><span class="o">(</span><span class="s">".burnees"</span><span class="o">).</span><span class="na">texts</span><span class="o">()).</span><span class="na">isEqualTo</span><span class="o">(</span><span class="nc">List</span><span class="o">.</span><span class="na">of</span><span class="o">(</span> <span class="s">"Сиг"</span><span class="o">,</span> <span class="s">"Оленегорский горняк"</span><span class="o">,</span> <span class="s">"Авиабаза Сольцы"</span><span class="o">,</span> <span class="s">"Чонгарский мост"</span><span class="o">,</span> <span class="s">"Гениченский мост"</span> <span class="o">));</span> </code></pre></div></div> <p>А с 6.16.0 стал возвращать тексты элементов вместе с пробелами:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">assertThat</span><span class="o">(</span><span class="err">$$</span><span class="o">(</span><span class="s">".burnees"</span><span class="o">).</span><span class="na">texts</span><span class="o">()).</span><span class="na">isEqualTo</span><span class="o">(</span><span class="nc">List</span><span class="o">.</span><span class="na">of</span><span class="o">(</span> <span class="s">" Сиг "</span><span class="o">,</span> <span class="s">" Оленегорский горняк "</span><span class="o">,</span> <span class="s">" Авиабаза Сольцы "</span><span class="o">,</span> <span class="s">" Чонгарский мост "</span><span class="o">,</span> <span class="s">" Гениченский мост "</span> <span class="o">));</span> </code></pre></div></div> <p>Возможно, это спорный вопрос, как правильно, но во всяком случае так работает стандартный метод <code class="language-plaintext highlighter-rouge">WebElement.getText()</code>. Спорить не стали. Теперь <code class="language-plaintext highlighter-rouge">$$.texts()</code> снова обрезает пробелы в голове и хвосте.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2419">issue 2419</a> и <a href="https://github.com/selenide/selenide/pull/2427">PR 2427</a>.</p> <p><br /></p> <center> <img src="/images/2023/08/restoration-independence-taasiseseisvumispaev-estonia.png" width="300" /> </center> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2023/08/20/selenide-6.17.1/ http://ru.selenide.org/2023/08/20/selenide-6.17.1 2023-08-20T00:00:00+00:00 Вышла Selenide 6.17.0 <p>Привіт!</p> <p>Погнали оновлюватись на <a href="https://github.com/selenide/selenide/milestone/187?closed=1">Selenide 6.17.0</a>!</p> <ul> <li><a href="#update-to-selenium-4.11.0">Обновились на Selenium 4.11.0</a></li> <li><a href="#replace-webdrivermanager-by-selenium-manager">Заменили WebDriverManager на SeleniumManager</a></li> <li><a href="#support-java8-again">Вернули поддержку Java 8</a></li> <li><a href="#add-method-type">Добавили метод <code class="language-plaintext highlighter-rouge">$.type()</code></a></li> <li><a href="#click-with-long-press">Новый метод для мобилок: клик с долгим нажатием</a></li> <li><a href="#swipe-right-and-left">Новый метод для мобилок: свайп влево и вправо</a></li> <li><a href="#statistics">Статистика</a> <p><br /></p> </li> </ul> <h3 id="update-to-selenium-4.11.0">Обновились на Selenium 4.11.0</h3> <p>Мы обновили версию Selenium с 4.10.0 на 4.11.0.</p> <p>Полный список изменений в Selenium <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">тут</a>.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2393">PR 2393</a>.</p> <p><br /></p> <h3 id="replace-webdrivermanager-by-selenium-manager">Заменили WebDriverManager на SeleniumManager</h3> <p>Начиная с версии 4.6.0, в Селениуме появился встроенный механизм для скачивания вебдрайверов - SeleniumManager. Насколько я понимаю, делает его всё тот же <a href="https://bonigarcia.dev/">Boni Garcia</a>, который создал и WebDriverManager. Только теперь он это делает официально как часть проекта Selenium.</p> <p>Подробнее про SeleniumManager <a href="https://www.selenium.dev/blog/2023/whats-new-in-selenium-manager-with-selenium-4.11.0/">тут</a>.</p> <p><strong>И теперь Selenide использует SeleniumManager вместо WebDriverManager.</strong></p> <ul> <li>Да, при этом нам пришлось удалить настройку <code class="language-plaintext highlighter-rouge">Configuration.driverManagerEnabled</code> и метод <code class="language-plaintext highlighter-rouge">DriverFactory.setupWebdriverBinary</code>. Возможно, у вас сломается компиляция.</li> <li>Да, немножко фигово, что мы сделали это <em>неожиданно</em>. Обычно мы не удаляем функционал сразу, а сначала помечаем его как <code class="language-plaintext highlighter-rouge">@Deprecated</code> и удаляем лишь в следующем мажорном релизе.</li> </ul> <p>Но у нас не осталось выбора.</p> <blockquote> <p>Давайте я покажу,<br /> откуда на WebDriverManager готовилось нападение?</p> </blockquote> <p>Начиная с версии 5.4.0, WDM начал требовать Java11+ и перестал работать с Chrome 115. А SeleniumManager и на Java 8 работает, и Chrome 115 поддерживает. И работает из коробки. <em>Что нам ещё оставалось?</em></p> <p>См. <a href="https://github.com/selenide/selenide/issues/2402">issue 2402</a> и <a href="https://github.com/selenide/selenide/pull/2400">PR 2400</a>.</p> <p><br /></p> <p>P.S. Если вы всё-таки очень хотите использовать WebDriverManager, не проблема: просто добавьте его в свои зависимости и вызывайте явно в начале тестов:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">WebDriverManager</span><span class="o">.</span><span class="na">chromedriver</span><span class="o">().</span><span class="na">setup</span><span class="o">();</span> <span class="nc">WebDriverManager</span><span class="o">.</span><span class="na">firefoxdriver</span><span class="o">().</span><span class="na">setup</span><span class="o">();</span> <span class="nc">WebDriverManager</span><span class="o">.</span><span class="na">edgedriver</span><span class="o">().</span><span class="na">setup</span><span class="o">();</span> <span class="n">etc</span><span class="o">.</span> </code></pre></div></div> <p><br /></p> <h3 id="support-java8-again">Вернули поддержку Java 8</h3> <p>В предыдущем релизе Selenide случайно стал требовать как минимум Java 11. Случилось это как раз из-за обновления WebDriverManager, который внезапно стал требовать Java 11.</p> <p>А теперь: нет WebDriverManager - нет проблемы. :)</p> <p>Олды, можете снова запускать свои тесты на Java 8.</p> <blockquote> <p>Тем не менее очень советую обновляться на Java 11 (а ещё лучше - на Java 17), потому что осенью Selenium перейдёт на Java 11. И тогда у вас точно не останется выбора.</p> </blockquote> <p>См. <a href="https://github.com/selenide/selenide/issues/2385">issue 2385</a> и <a href="https://github.com/selenide/selenide/pull/2400">PR 2400</a>.</p> <p><br /></p> <h3 id="add-method-type">Добавили метод <code class="language-plaintext highlighter-rouge">$.type()</code></h3> <p>Эту фичу очень давно просили. И вот наконец!</p> <p><code class="language-plaintext highlighter-rouge">$.type()</code> - это то же, что <code class="language-plaintext highlighter-rouge">$.sendKeys()</code>, но с задержками. Типа эмуляция того, как реальный пользователь вводит текст.<br /> Может быть полезно, чтобы сработали автоматические подсказки, автозамена или ещё что-нибудь подобное.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">TypeOptions</span><span class="o">.*;</span> <span class="err">$</span><span class="o">(</span><span class="s">"#query"</span><span class="o">).</span><span class="na">type</span><span class="o">(</span><span class="s">"Who the fuck is yevgeny prigozhin"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#query"</span><span class="o">).</span><span class="na">type</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Who the fuck is dmitry utkin"</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">"#query"</span><span class="o">).</span><span class="na">type</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Who the fuck is lvova-belova"</span><span class="o">).</span><span class="na">withDelay</span><span class="o">(</span><span class="n">ofMillis</span><span class="o">(</span><span class="mi">100</span><span class="o">)));</span> </code></pre></div></div> <p>По умолчанию задержка между “нажатиями клавиш” - 200 миллисекунд.</p> <p>Спасибо <a href="https://github.com/amuthansakthivel">Amuthan Sakthivel</a> за <a href="https://github.com/selenide/selenide/pull/2191">PR 2191</a>.</p> <p><br /></p> <h3 id="click-with-long-press">Новый метод для мобилок: клик с долгим нажатием</h3> <p>Теперь можно делать так:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">SelenideAppium</span><span class="o">.</span><span class="err">$</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">AppiumClickOptions</span><span class="o">.*;</span> <span class="err">$</span><span class="o">.</span><span class="na">click</span><span class="o">(</span><span class="n">longPress</span><span class="o">());</span> <span class="c1">// by default 3 seconds</span> <span class="err">$</span><span class="o">.</span><span class="na">click</span><span class="o">(</span><span class="n">longPressFor</span><span class="o">(</span><span class="nc">Duration</span><span class="o">.</span><span class="na">ofSeconds</span><span class="o">(</span><span class="mi">4</span><span class="o">)));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2370">issue 2370</a>. Спасибо <a href="https://github.com/amuthansakthivel">Amuthan Sakthivel</a> за <a href="https://github.com/selenide/selenide/pull/2381">PR 2381</a>.</p> <p><br /></p> <h3 id="swipe-right-and-left">Новый метод для мобилок: свайп влево и вправо</h3> <p>А ещё теперь можно делать так:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">SelenideAppium</span><span class="o">.</span><span class="err">$</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">AppiumSwipeOptions</span><span class="o">.*;</span> <span class="err">$</span><span class="o">.</span><span class="na">swipeTo</span><span class="o">();</span> <span class="c1">// by default swipes to the right</span> <span class="err">$</span><span class="o">.</span><span class="na">swipe</span><span class="o">(</span><span class="n">right</span><span class="o">());</span> <span class="err">$</span><span class="o">.</span><span class="na">swipe</span><span class="o">(</span><span class="n">right</span><span class="o">(</span><span class="mi">20</span><span class="o">));</span> <span class="err">$</span><span class="o">.</span><span class="na">swipe</span><span class="o">(</span><span class="n">left</span><span class="o">());</span> <span class="err">$</span><span class="o">.</span><span class="na">swipe</span><span class="o">(</span><span class="n">left</span><span class="o">(</span><span class="mi">30</span><span class="o">));</span> </code></pre></div></div> <p>Спасибо <a href="https://github.com/amuthansakthivel">Amuthan Sakthivel</a> за <a href="https://github.com/selenide/selenide/pull/2369">PR 2369</a>.</p> <p><br /></p> <p>В общем, обновляйтесь, пробуйте, делитесь:</p> <blockquote> <p>как вам SeleniumManager?<br /> Всё вообще сломалось, или можно жить?</p> </blockquote> <p><br /></p> <h3 id="statistics">Статистика</h3> <p>Количество ежемесячных скачиваний Селенида перевалило за 649 тыщ!</p> <center> <img src="/images/2023/07/selenide.downloads.png" width="800" /> </center> <p>(Предыдущий рекорд был в марте: 602 тыщи)</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2023/08/02/selenide-6.17.0/ http://ru.selenide.org/2023/08/02/selenide-6.17.0 2023-08-02T00:00:00+00:00 Вышла Selenide 6.16.1 <p>Привет, пипл!</p> <p>Мы выпустили небольшое обновление <a href="https://github.com/selenide/selenide/milestone/186?closed=1">Selenide 6.16.1</a>.</p> <ul> <li><a href="#all-of-and-any-of-conditions">Добавили условия <code class="language-plaintext highlighter-rouge">allOf</code> и <code class="language-plaintext highlighter-rouge">anyOf</code></a></li> <li><a href="#add-checks-for-cookies">Добавили проверки для cookies</a></li> <li><a href="#update-webdrivermanager">Обновили WebDriverManager</a></li> <li><a href="#support-tspan-in-svg">Исправили проверку текстов <code class="language-plaintext highlighter-rouge">&lt;tspan&gt;</code> в SVG</a> <p><br /></p> </li> </ul> <h3 id="all-of-and-any-of-conditions">Добавили условия <code class="language-plaintext highlighter-rouge">allOf</code> и <code class="language-plaintext highlighter-rouge">anyOf</code></h3> <p>Теперь можно проверить одно из нескольких условий (OR):</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#president"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">anyOf</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Ничтожество"</span><span class="o">),</span> <span class="n">text</span><span class="o">(</span><span class="s">"Трусливый бездарь"</span><span class="o">)));</span> </code></pre></div></div> <p>(на самом деле для этого и раньше был метод <code class="language-plaintext highlighter-rouge">Condition.or</code>, но <code class="language-plaintext highlighter-rouge">anyOf</code> как будто чуть удобнее).</p> <p>Также можно проверить совпадение всех условий сразу (AND):</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#generals"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">allOf</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"бездарней"</span><span class="o">),</span> <span class="n">text</span><span class="o">(</span><span class="s">"ничтожней"</span><span class="o">)));</span> </code></pre></div></div> <p>(на самом деле это то же самое, что и <code class="language-plaintext highlighter-rouge">$("#generals").shouldHave(text("бездарней"), text("ничтожней"))</code>, но зато результат <code class="language-plaintext highlighter-rouge">allOf</code> можно вынести в переменную или метод, создав таким образом своё условие).</p> <p>Спасибо <a href="https://github.com/evpl">Evgenii Plugatar</a> за <a href="https://github.com/selenide/selenide/pull/2368">PR 2368</a>.</p> <p><br /></p> <h3 id="add-checks-for-cookies">Добавили проверки для cookies</h3> <p>Теперь можно проверять кукисы в браузере:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">Selenide</span><span class="o">.</span><span class="na">webdriver</span><span class="o">;</span> <span class="n">webdriver</span><span class="o">().</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">cookie</span><span class="o">(</span><span class="s">"session_id"</span><span class="o">));</span> <span class="n">webdriver</span><span class="o">().</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">cookie</span><span class="o">(</span><span class="s">"session_id"</span><span class="o">,</span> <span class="s">"1234567890"</span><span class="o">));</span> <span class="n">webdriver</span><span class="o">().</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">cookie</span><span class="o">(</span><span class="s">"session_id"</span><span class="o">,</span> <span class="s">"1234567890"</span><span class="o">,</span> <span class="nc">Duration</span><span class="o">.</span><span class="na">ofSeconds</span><span class="o">(</span><span class="mi">10</span><span class="o">)));</span> </code></pre></div></div> <p>С ожиданием результата, кастомным таймаутом и скриншотами при падении - всё, как вы любите.</p> <p>Спасибо <a href="https://github.com/adorne">adorne</a> за <a href="https://github.com/selenide/selenide/pull/2367">PR 2367</a>.</p> <p><br /></p> <h3 id="update-webdrivermanager">Обновили WebDriverManager с 5.4.0 до 5.4.1</h3> <p>Среди прочего, там добавлена поддержка Chrome 115, с которым у многих возникли проблемы.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2374">PR 2374</a>.</p> <p>P.S. На маках Chrome 115 в данный момент не работает. Выскакивает такая ошибка:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SessionNotCreatedException: Could not start a new session. Response code 500. Message: unknown error: cannot find Chrome binary </code></pre></div></div> <p>Но мы не виноваты, это <a href="https://github.com/GoogleChromeLabs/chrome-for-testing/issues/30">бага в chromedriver</a>. Обещали скоро исправить.</p> <p><br /></p> <h3 id="support-tspan-in-svg">Исправили проверку текстов <code class="language-plaintext highlighter-rouge">&lt;tspan&gt;</code> в SVG</h3> <p>Вы когда-нибудь проверяли тексты внутри SVG? Я тоже нет. А они там, оказывается, есть!</p> <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt">&lt;svg&gt;</span> <span class="nt">&lt;text</span> <span class="na">x=</span><span class="s">"10"</span> <span class="na">y=</span><span class="s">"30"</span> <span class="na">class=</span><span class="s">"small"</span><span class="nt">&gt;</span> Люди хотят <span class="nt">&lt;tspan&gt;</span>благодарности<span class="nt">&lt;/tspan&gt;</span>. <span class="nt">&lt;/text&gt;</span> <span class="nt">&lt;text</span> <span class="na">x=</span><span class="s">"10"</span> <span class="na">y=</span><span class="s">"60"</span> <span class="na">class=</span><span class="s">"small"</span><span class="nt">&gt;</span> Мы не склад <span class="nt">&lt;tspan&gt;</span>Amazon<span class="nt">&lt;/tspan&gt;</span>. <span class="nt">&lt;/text&gt;</span> <span class="nt">&lt;text</span> <span class="na">x=</span><span class="s">"10"</span> <span class="na">y=</span><span class="s">"90"</span> <span class="na">class=</span><span class="s">"small"</span><span class="nt">&gt;</span> Спасибо тебе, <span class="nt">&lt;tspan&gt;</span>Бен Уоллес<span class="nt">&lt;/tspan&gt;</span>! <span class="nt">&lt;/text&gt;</span> <span class="nt">&lt;/svg&gt;</span> </code></pre></div></div> <p>И теперь их снова можно проверять:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$$</span><span class="o">(</span><span class="s">"svg tspan"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">texts</span><span class="o">(</span><span class="s">"благодарности"</span><span class="o">,</span> <span class="s">"Amazon"</span><span class="o">,</span> <span class="s">"Бен Уоллес"</span><span class="o">));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2377">issue 2377</a> и <a href="https://github.com/selenide/selenide/pull/2379">PR 2379</a>.</p> <p><br /> <br /></p> <center> <img src="/images/2023/07/ben-wallace.png" width="600" /> </center> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2023/07/24/selenide-6.16.1/ http://ru.selenide.org/2023/07/24/selenide-6.16.1 2023-07-24T00:00:00+00:00 Вышла Selenide 6.16.0 <p>Доброй ночи!</p> <blockquote> <p>У меня к вам предложение, от которого лучше не отказываться.</p> </blockquote> <p>Обновляйтесь на <a href="https://github.com/selenide/selenide/milestone/185?closed=1">Selenide 6.16.0</a>!</p> <ul> <li><a href="#speedup-collection-checks">Ускорили проверки коллекций</a></li> <li><a href="#improve-collections-error-messages">Улучшили сообщение об ошибках в коллекциях</a></li> <li><a href="#new-date-checks">Новые проверки для дат <code class="language-plaintext highlighter-rouge">date(...)</code> и <code class="language-plaintext highlighter-rouge">datetime(...)</code></a></li> <li><a href="#set-date-time-value">Новые методы для установки времени</a></li> <li><a href="#full-stacktrace-in-soft-asserts">Полный стектрейс в софт ассертах</a></li> <li><a href="#improve-basic-auth-in-chromium-browsers">BasicAuth в браузерах Chromium</a></li> <li><a href="#multiple-domains-in-basic-auth">Несколько доменов в BasicAuth</a></li> <li><a href="#fix-double-click-in-appium">Исправили <code class="language-plaintext highlighter-rouge">$.doubleClick()</code> в Appium</a></li> <li><a href="#screenshot-before-after-each">Снимаем скриншот чуть раньше</a></li> <li><a href="#update-dependencies">Обновили зависимости</a></li> <li><a href="#news">Новости</a> <p><br /></p> </li> </ul> <h3 id="speedup-collection-checks">Ускорили проверки коллекций</h3> <p>Вот это крутизна!</p> <p>Как вы знаете, одна из базовых возможностей в Селениде - это проверки коллекций. Одной строчкой можно проверить сразу кучу элементов:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$$</span><span class="o">(</span><span class="s">"option"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">texts</span><span class="o">(</span><span class="s">"Шмякино"</span><span class="o">,</span> <span class="s">"Шебекино"</span><span class="o">,</span> <span class="s">"Шелебякино"</span><span class="o">,</span> <span class="s">"Шлёпкино"</span><span class="o">))</span> </code></pre></div></div> <p>Однако <strong>такая проверка занимает время</strong>, если коллекция достаточно большая.</p> <p>Например, если на странице 1000 элементов <code class="language-plaintext highlighter-rouge">&lt;option&gt;</code>, на моём компе она занимает почти 3 секунды.<br /> Медленность обусловлена тем, что Селенид спрашивает у браузера текст каждого элемента по отдельности. 1000 вызовов вебдрайвера, даже очень быстрых - это долго.</p> <p>Пришло время ускорить эти проверки.</p> <p>Теперь Селенид запрашивает тексты всех 1000 элементов <strong>за один вызов вебдрайвера</strong> с помощью JavaScript.</p> <blockquote> <p>Теперь та проверка вместо 3 секунд занимает 200 мс.<br /> В 15 раз быстрее.<br /> <em>Ну очуметь же!</em></p> </blockquote> <p>P.S. Для Appium и других возможных вебдрайверов, которые не поддерживают JS, остаётся старый вариант (который запрашивает тексты по одному). Что поделать. Хотя бы не стало хуже.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2362">PR 2362</a>.</p> <p><br /></p> <h3 id="improve-collections-error-messages">Улучшили сообщение об ошибках в коллекциях</h3> <p>В рамках предыдущей переделки проверок для коллекций мы чутка дополнили и сообщения об ошибках. Теперь Селенид точнее говорит, <em>какой именно элемент коллекции не совпал</em>.</p> <p>Например, вот такая проверка:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$$</span><span class="o">(</span><span class="s">".direction"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">texts</span><span class="o">(</span> <span class="s">"На Ростов"</span><span class="o">,</span> <span class="s">"На Москву"</span><span class="o">,</span> <span class="s">"В полевые лагеря согласно плану"</span><span class="o">));</span> </code></pre></div></div> <p>Раньше выдавала просто <code class="language-plaintext highlighter-rouge">"Texts mismatch"</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Texts</span> <span class="n">mismatch</span> <span class="nl">Actual:</span> <span class="o">[</span><span class="nc">На</span> <span class="nc">Ростов</span><span class="o">,</span> <span class="nc">На</span> <span class="nc">Москву</span><span class="o">,</span> <span class="no">В</span> <span class="nc">Беларусь</span><span class="o">]</span> <span class="nl">Expected:</span> <span class="o">[</span><span class="nc">На</span> <span class="nc">Ростов</span><span class="o">,</span> <span class="nc">На</span> <span class="nc">Москву</span><span class="o">,</span> <span class="no">В</span> <span class="n">полевые</span> <span class="n">лагеря</span> <span class="n">согласно</span> <span class="n">плану</span><span class="o">]</span> </code></pre></div></div> <p>А теперь первая строка содержит более точное указание, что именно не совпало:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Text</span> <span class="err">#</span><span class="mi">2</span> <span class="n">mismatch</span> <span class="o">(</span><span class="nl">expected:</span> <span class="s">"В полевые лагеря согласно плану"</span><span class="o">,</span> <span class="nl">actual:</span> <span class="s">"В Беларусь"</span><span class="o">)</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/pull/2362">PR 2362</a>.</p> <p><br /></p> <h3 id="new-date-checks">Новые проверки для дат <code class="language-plaintext highlighter-rouge">date(...)</code> и <code class="language-plaintext highlighter-rouge">datetime(...)</code></h3> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">conditions</span><span class="o">.</span><span class="na">datetime</span><span class="o">.</span><span class="na">DateConditionOptions</span><span class="o">.*;</span> <span class="nc">LocalDate</span> <span class="n">theDay</span> <span class="o">=</span> <span class="nc">LocalDate</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="mi">2023</span><span class="o">,</span> <span class="mi">6</span><span class="o">,</span> <span class="mi">23</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#funParty"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">date</span><span class="o">(</span><span class="n">theDay</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">"#funParty"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">date</span><span class="o">(</span><span class="n">theDay</span><span class="o">,</span> <span class="s">"yyyy-MM-dd"</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">"#funParty"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">dateBetween</span><span class="o">(</span><span class="n">parse</span><span class="o">(</span><span class="s">"2023-06-22"</span><span class="o">),</span> <span class="n">parse</span><span class="o">(</span><span class="s">"2023-06-24"</span><span class="o">)));</span> <span class="err">$</span><span class="o">(</span><span class="s">"#funParty"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">dateFormat</span><span class="o">(</span><span class="s">"yyyy-MM-dd"</span><span class="o">));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2268">issue 2268</a>. Спасибо <a href="https://github.com/Au6ojlut">Maksim @Au6ojlut</a> за <a href="https://github.com/selenide/selenide/pull/2281">PR 2281</a>.</p> <p><br /></p> <h3 id="set-date-time-value">Новые методы для установки времени</h3> <p>В селениде уже был метод для установки даты (<code class="language-plaintext highlighter-rouge">withDate</code>):</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">LocalDate</span> <span class="n">theDay</span> <span class="o">=</span> <span class="nc">LocalDate</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="mi">2023</span><span class="o">,</span> <span class="mi">6</span><span class="o">,</span> <span class="mi">23</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#euphoriaDay"</span><span class="o">).</span><span class="na">setValue</span><span class="o">(</span><span class="n">withDate</span><span class="o">(</span><span class="n">theDay</span><span class="o">));</span> <span class="c1">// для &lt;input type="date"&gt;</span> </code></pre></div></div> <p>Теперь же мы добавили похожие методы для установки даты с временем (<code class="language-plaintext highlighter-rouge">withDateTime</code>):</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#epicFail"</span><span class="o">).</span><span class="na">setValue</span><span class="o">(</span><span class="n">withDateTime</span><span class="o">(</span><span class="nc">LocalDateTime</span><span class="o">.</span><span class="na">parse</span><span class="o">(</span><span class="s">"2023-06-23 20:29"</span><span class="o">)));</span> <span class="c1">// для &lt;input type="datetime-local"&gt;</span> </code></pre></div></div> <p>либо только времени (<code class="language-plaintext highlighter-rouge">withTime</code>):</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#rostov"</span><span class="o">).</span><span class="na">setValue</span><span class="o">(</span><span class="n">withTime</span><span class="o">(</span><span class="nc">LocalTime</span><span class="o">.</span><span class="na">parse</span><span class="o">(</span><span class="s">"07:00"</span><span class="o">)));</span> <span class="err">$</span><span class="o">(</span><span class="s">"#voronezh"</span><span class="o">).</span><span class="na">setValue</span><span class="o">(</span><span class="n">withTime</span><span class="o">(</span><span class="nc">LocalTime</span><span class="o">.</span><span class="na">parse</span><span class="o">(</span><span class="s">"14:00"</span><span class="o">)));</span> <span class="err">$</span><span class="o">(</span><span class="s">"#lipetsk"</span><span class="o">).</span><span class="na">setValue</span><span class="o">(</span><span class="n">withTime</span><span class="o">(</span><span class="nc">LocalTime</span><span class="o">.</span><span class="na">parse</span><span class="o">(</span><span class="s">"16:00"</span><span class="o">)));</span> <span class="err">$</span><span class="o">(</span><span class="s">"#moskva-reka"</span><span class="o">).</span><span class="na">setValue</span><span class="o">(</span><span class="n">withTime</span><span class="o">(</span><span class="nc">LocalTime</span><span class="o">.</span><span class="na">parse</span><span class="o">(</span><span class="s">"20:20"</span><span class="o">)));</span> <span class="c1">// для &lt;input type="time"&gt;</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/pull/2357">PR 2357</a>.</p> <p><br /></p> <h3 id="full-stacktrace-in-soft-asserts">Полный стектрейс в софт ассертах</h3> <p>В Селениде уже давно есть софт ассерты. Когда вы включаете этот режим, при падении нескольких проверок Селенид кидает ошибку не сразу, а лишь в конце теста. И в этой ошибке перечисляются все Assertion error.</p> <p>Вопрос в том, что для этих ошибок Селенид показывал <strong>неполный стектрейс</strong>, и там не была видна часть “Caused by:”. Теперь будет видна. Будьте готовы к тому, что длина стектрейсов резко вырастет :).</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2350">issue 2350</a> и <a href="https://github.com/selenide/selenide/pull/2354">PR 2354</a>.</p> <p><br /></p> <h3 id="improve-basic-auth-in-chromium-browsers">Улучшили BasicAuth в браузерах семейства Chromium</h3> <p>В Селениде есть методы для авторизации на странице через BasicAuth:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">open</span><span class="o">(</span><span class="s">"/basic-auth/hello"</span><span class="o">,</span> <span class="s">""</span><span class="o">,</span> <span class="s">"admin"</span><span class="o">,</span> <span class="s">"Казкова діброва"</span><span class="o">);</span> </code></pre></div></div> <p>До сих пор было две реализации BasicAuth.</p> <ol> <li>При включённом прокси: Селенид добавляет к запросу заголовок <code class="language-plaintext highlighter-rouge">Authorization</code> (<code class="language-plaintext highlighter-rouge">Basic YWRtaW460JrQsNC30LrQvtCy0LAg0LTRltCx0YDQvtCy0LA=</code>).</li> <li>При выключенном прокси: Селенид добавляет логин и пароль в URL (<code class="language-plaintext highlighter-rouge">https://admin:Казкова+діброва@localhost:42220/basic-auth/hello</code>).</li> </ol> <p>Теперь к ним добавился третий вариант: Если вебдрайвер реализует интерфейс <code class="language-plaintext highlighter-rouge">org.openqa.selenium.HasAuthentication</code>, Селенид добавляет логин+пароль через него. Фактически это означает браузеры семейства Chromium (Chrome, Chromium, Edge).</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2336">issue 2336</a> и <a href="https://github.com/selenide/selenide/pull/2358">PR 2358</a>.</p> <p><br /></p> <h3 id="multiple-domains-in-basic-auth">Несколько доменов в BasicAuth</h3> <p>До сих пор можно было прописать только один домен для BasicAuth:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">open</span><span class="o">(</span><span class="s">"/basic-auth/hello"</span><span class="o">,</span> <span class="s">"mister-cider.ru"</span><span class="o">,</span> <span class="s">"luka"</span><span class="o">,</span> <span class="s">"картофельный спас"</span><span class="o">);</span> </code></pre></div></div> <p>Это не помогает, если в тестируемом приложении задействовано несколько доменов - например, оно открывает фреймы с адресом <code class="language-plaintext highlighter-rouge">auth.mister-cider.ru</code> или там <code class="language-plaintext highlighter-rouge">api.mister-cider.ru</code>. Всегда можно прописать пустую строку вместо домена, но у этого варианта есть <a href="/2022/10/07/selenide-6.9.0/#secure-authorization-header">очевидные минусы</a>.</p> <p>Теперь можно прописать несколько доменов через запятую или “|”:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">open</span><span class="o">(</span><span class="s">"/basic-auth/hello"</span><span class="o">,</span> <span class="s">"mister-cider.ru|auth.mister-cider.ru|api.mister-cider.ru"</span><span class="o">,</span> <span class="s">"luka"</span><span class="o">,</span> <span class="s">"картофельный спас"</span><span class="o">);</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/pull/2358">PR 2358</a>.</p> <p>P.S. Естественно, имя домена не используется, когда Селенид добавляет логин+пароль просто в URL.</p> <p><br /></p> <h3 id="fix-double-click-in-appium">Исправили <code class="language-plaintext highlighter-rouge">$.doubleClick()</code> в Appium</h3> <p>В предыдущем релизе мы сломали, а теперь починили двойной клик в мобильниках:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="nc">AppiumBy</span><span class="o">.</span><span class="na">xpath</span><span class="o">(</span><span class="s">".//android.widget.CheckBox"</span><span class="o">)).</span><span class="na">doubleClick</span><span class="o">();</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2346">issue 2346</a> и <a href="https://github.com/selenide/selenide/pull/2347">PR 2347</a>.</p> <p><br /></p> <h3 id="screenshot-before-after-each">Снимаем скриншот чуть раньше</h3> <p>Обычно Селенид автоматически делает скриншот в случае падения теста. НО Если вы закрывали браузер в методе <code class="language-plaintext highlighter-rouge">@AfterEach</code>, то Селенид уже не мог сделать скриншот:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@AfterEach</span> <span class="kt">void</span> <span class="nf">tearDown</span><span class="o">()</span> <span class="o">{</span> <span class="nc">Selenide</span><span class="o">.</span><span class="na">closeWebDriver</span><span class="o">();</span> <span class="o">}</span> </code></pre></div></div> <p>Теперь Селенид будет делать скриншот чуть раньше - ДО методов <code class="language-plaintext highlighter-rouge">@AfterEach</code>.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2352">issue 2352</a> и <a href="https://github.com/selenide/selenide/pull/2356">PR 2356</a>.</p> <p><br /></p> <h3 id="update-dependencies">Обновили зависимости</h3> <ul> <li><a href="https://github.com/selenide/selenide/pull/2318">2319</a> use latest version of geckodriver for FF 102+</li> <li><a href="https://github.com/selenide/selenide/pull/2328">2328</a> bump Selenium from 4.9.1 to 4.10.0</li> <li><a href="https://github.com/selenide/selenide/pull/2324">2324</a> Bump io.appium:java-client from 8.5.0 to 8.5.1</li> <li><a href="https://github.com/selenide/selenide/pull/2349">2349</a> Bump Netty from 4.1.93.Final to 4.1.94.Final</li> <li>bump WebDriverManager from 5.3.3 to 5.4.0</li> </ul> <p><br /></p> <h3 id="news">Новости</h3> <ul> <li>Пост <a href="https://www.it-notes.wiki/automation-testing/page-object-simple-example-using-selenide/">Page Object – простой пример с использованием Selenide</a> на IT-notes</li> <li>Видос <a href="https://www.youtube.com/watch?v=zAhCLLX9IOc&amp;ab_channel=TestingMiniBytes">Run Selenide Appium Test in LambdaTest</a> в блоге “Testing Mini Bytes”</li> </ul> <p><br /></p> <blockquote> <p>Ну что, нормальный результат, я считаю.<br /> ВСЕХ ВЗБОДРИЛИ!!!<br /> Счастливо!</p> </blockquote> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2023/07/02/selenide-6.16.0/ http://ru.selenide.org/2023/07/02/selenide-6.16.0 2023-07-02T00:00:00+00:00 Вышла Selenide 6.15.0 <p>Доброй ночи!</p> <blockquote> <p>Есть люди, которые постоянно деплоят, а есть люди, которые один раз в жизни где-то выучили, что должен быть РЕЛИЗ — и копят, копят, копят фичи для этого релиза. <br /> А счастливый дедушка-мейнтейнер думает, что ему хорошо.<br /> И как использовать опенсорс-проект, если вдруг случайно окажется, что этот дедушка — законченный мудак?</p> </blockquote> <p>Как вы поняли, мы выпустили новую версию <a href="https://github.com/selenide/selenide/milestone/184?closed=1">Selenide 6.15.0</a> с серьёзными такими внутренними переделками.</p> <ul> <li><a href="#merge-selenide-selenoid-to-selenide">Влили проект <code class="language-plaintext highlighter-rouge">selenide-selenoid</code> в <code class="language-plaintext highlighter-rouge">selenide</code></a></li> <li><a href="#merge-selenide-appium-to-selenide">Влили проект <code class="language-plaintext highlighter-rouge">selenide-appium</code> в <code class="language-plaintext highlighter-rouge">selenide</code></a></li> <li><a href="#clicking-disable-element-fails">Клик теперь проверяет, что элемент не disabled</a></li> <li><a href="#escape-newlines-in-report">Маскируем переводы строк в отчёте</a></li> <li><a href="#combined-selectors-for-mobile-apps">Комбинированные селекторы для мобилок</a></li> <li><a href="#conditions-for-mobile-apps">Новые проверки для мобилок</a></li> <li><a href="#new-selectors-for-mobile-apps">Новые селекторы для мобилок</a></li> <li><a href="#switch-context-in-mobile-apps">Переключение контекста в мобилках</a></li> <li><a href="#refactor-collection-conditions">Переколбас CollectionCondition</a></li> <li><a href="#news">Новости</a> <p><br /></p> </li> </ul> <h3 id="merge-selenide-selenoid-to-selenide">Влили проект <code class="language-plaintext highlighter-rouge">selenide-selenoid</code> в <code class="language-plaintext highlighter-rouge">selenide</code></h3> <p>Это позволит нам легче менять и релизить эти проекты. Для вас поменяется объявление зависимости. Вместо</p> <div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">testImplementation</span><span class="o">(</span><span class="s2">"org.selenide:selenide-selenoid:2.3.7"</span><span class="o">)</span> </code></pre></div></div> <p>Теперь нужно будет прописать:</p> <div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">testImplementation</span><span class="o">(</span><span class="s2">"com.codeborne:selenide-selenoid:6.15.0"</span><span class="o">)</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/pull/2292">PR 2292</a>.</p> <p><br /></p> <h3 id="merge-selenide-appium-to-selenide">Влили проект <code class="language-plaintext highlighter-rouge">selenide-appium</code> в <code class="language-plaintext highlighter-rouge">selenide</code></h3> <p>Это позволит нам легче менять и релизить эти проекты. Вам всего лишь нужно будет обновить версию <code class="language-plaintext highlighter-rouge">selenide-appium</code> с <code class="language-plaintext highlighter-rouge">2.8.1</code> на <code class="language-plaintext highlighter-rouge">6.15.0</code></p> <p>См. <a href="https://github.com/selenide/selenide/pull/2291">PR 2291</a>.</p> <p><br /></p> <h3 id="clicking-disable-element-fails">Клик теперь проверяет, что элемент не disabled</h3> <p>Как вы знаете, метод <code class="language-plaintext highlighter-rouge">$.click()</code> требует, чтобы элемент был видимым (более точно: либо элемент должен быть видимый, либо иметь css свойство <code class="language-plaintext highlighter-rouge">opacity: 0</code>).</p> <p>НО до сих пор Селенид не проверял, что элемент enabled. Другими словами,</p> <blockquote> <p>Селенид разрешал кликать на <code class="language-plaintext highlighter-rouge">disabled</code> элементы.</p> </blockquote> <ol> <li><strong>В пользу</strong> этого решения был такой аргумент: а вдруг автор теста и хочет кликнуть на задизейбленый элемент и убедиться, что ничего не произошло?</li> <li><strong>Против</strong> этого решения был другой аргумент: такое поведение может спровоцировать нестабильные тесты: <ul> <li>тест кликает на кнопку, не дожидаясь, пока она станет enabled</li> <li>по факту клик не случится (но и никаких ошибок не возникнет)</li> <li>и позже тест упадёт из-за не случившегося клика (и будет очень сложно понять, что произошло)</li> <li>или ещё хуже: тест может остаться ложно позитивным.</li> </ul> </li> </ol> <p>В общем, теперь <strong>аргумент №2 победил</strong>. Теперь метод <code class="language-plaintext highlighter-rouge">$.click()</code> дождётся, пока элемент станет enabled. А если не станет - клик упадёт.</p> <p>Теперь вы можете смело сократить все свои тесты:</p> <blockquote> <p><code class="language-plaintext highlighter-rouge">$.shouldBe(enabled).click()</code> заменить на <code class="language-plaintext highlighter-rouge">$.click()</code>.</p> </blockquote> <p>P.S. Если вы из лагеря аргумента №1, то можете вместо клика использовать <code class="language-plaintext highlighter-rouge">$.shouldBe(disabled)</code>.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2288">issue 2288</a>. Спасибо <a href="https://github.com/Au6ojlut">Maksim @Au6ojlut</a> за <a href="https://github.com/selenide/selenide/pull/2290">PR 2290</a>.</p> <p><br /></p> <h3 id="escape-newlines-in-report">Маскируем переводы строк в отчёте</h3> <p>Если вы пробовали использовать в тесте многострочную строку:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Если\n дедушка\n законченный\n мудак"</span><span class="o">);</span> </code></pre></div></div> <p>То могли заметить, что в отчёте эта строка выглядела коряво и ломала всю таблицу.</p> <p>А теперь будет красиво.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2283">issue 2283</a>. Спасибо <a href="https://github.com/Au6ojlut">Maksim @Au6ojlut</a> за <a href="https://github.com/selenide/selenide/pull/2284">PR 2284</a>.</p> <p><br /></p> <h3 id="combined-selectors-for-mobile-apps">Комбинированные селекторы для мобилок</h3> <p>При тестировании мобильных приложений удобно задать в одной проверке два селектора: отдельно для Android и iOS.<br /> Раньше приходилось придумывать вспомогательные методы или городить ифы.</p> <p>Теперь же можно объявить “комбинированный” селектор с помощью <code class="language-plaintext highlighter-rouge">CombinedBy</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">selector</span><span class="o">.</span><span class="na">CombinedBy</span><span class="o">.</span><span class="na">android</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">AppiumSelectors</span><span class="o">.</span><span class="na">byTagAndName</span><span class="o">;</span> <span class="err">$</span><span class="o">(</span><span class="n">android</span><span class="o">(</span><span class="n">byText</span><span class="o">(</span><span class="s">"Бибер"</span><span class="o">)).</span><span class="na">ios</span><span class="o">(</span><span class="n">byText</span><span class="o">(</span><span class="s">"Долик"</span><span class="o">)))</span> <span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Бибер"</span><span class="o">));</span> </code></pre></div></div> <p><br /></p> <h3 id="conditions-for-mobile-apps">Новые проверки для мобилок</h3> <p>Аналогичное решение для проверок: теперь можно одной строкой задать “комбинированную” проверку и для Android, и для iOS с помощью класса <code class="language-plaintext highlighter-rouge">CombinedAttribute</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">conditions</span><span class="o">.</span><span class="na">CombinedAttribute</span><span class="o">.</span><span class="na">android</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">AppiumCondition</span><span class="o">.</span><span class="na">attribute</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">static</span> <span class="n">io</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">java_client</span><span class="o">.</span><span class="na">AppiumBy</span><span class="o">.</span><span class="na">accessibilityId</span><span class="o">;</span> <span class="c1">// Проверка элемента:</span> <span class="err">$</span><span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">attribute</span><span class="o">(</span> <span class="n">android</span><span class="o">(</span><span class="s">"content-desc"</span><span class="o">).</span><span class="na">ios</span><span class="o">(</span><span class="s">"name"</span><span class="o">),</span> <span class="s">"Гойду, Жерасимов, где, сука, ебоприпасы?"</span> <span class="o">));</span> <span class="c1">// Проверка коллекции:</span> <span class="err">$$</span><span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">attributes</span><span class="o">(</span><span class="n">android</span><span class="o">(</span><span class="s">"text"</span><span class="o">),</span> <span class="s">"Бздила картонный"</span><span class="o">,</span> <span class="s">"Болтун безмозглый"</span><span class="o">,</span> <span class="s">"Вазелиновая коррекция"</span><span class="o">,</span> <span class="s">"Зять-«у*бок»"</span><span class="o">,</span> <span class="s">"Сын-отморозок"</span> <span class="o">));</span> </code></pre></div></div> <p><br /></p> <h3 id="new-selectors-for-mobile-apps">Новые селекторы для мобилок</h3> <p>Для кучи, нас появилась пачка новых селекторов для поиска элементов по тэгу, тексту, подстроке и т.п.:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">AppiumSelectors</span><span class="o">.*;</span> <span class="err">$</span><span class="o">(</span><span class="n">byAttribute</span><span class="o">(</span><span class="s">"content-desc"</span><span class="o">,</span> <span class="s">"Hello"</span><span class="o">)).</span><span class="na">click</span><span class="o">();</span> <span class="err">$</span><span class="o">(</span><span class="n">byContentDescription</span><span class="o">(</span><span class="s">"Hello"</span><span class="o">)).</span><span class="na">click</span><span class="o">();</span> <span class="err">$</span><span class="o">(</span><span class="n">byTagAndAtttribute</span><span class="o">(</span><span class="s">"android.widget.TextView"</span><span class="o">,</span> <span class="s">"Не"</span><span class="o">)).</span><span class="na">click</span><span class="o">();</span> <span class="err">$</span><span class="o">(</span><span class="n">byTagAndName</span><span class="o">(</span><span class="s">"XCUIElementTypeStaticText"</span><span class="o">,</span> <span class="s">"вы е"</span><span class="o">)).</span><span class="na">click</span><span class="o">();</span> <span class="err">$</span><span class="o">(</span><span class="n">withTagAndName</span><span class="o">(</span><span class="s">"XCUIElementTypeText"</span><span class="o">,</span> <span class="s">"бываться на красной площади"</span><span class="o">)).</span><span class="na">click</span><span class="o">();</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2300">issue 2300</a>. Спасибо <a href="https://github.com/amuthansakthivel">Amuthan Sakthivel</a> за <a href="https://github.com/selenide/selenide-appium/pull/135">PR 135</a>. Также см. <a href="https://github.com/selenide/selenide/pull/2315">PR 2315</a>.</p> <p><br /></p> <h3 id="switch-context-in-mobile-apps">Переключение контекста в мобилках</h3> <p>Зачастую мобильные приложения открывают какой-то контент во встроенном браузере (WebView). А то и полностью построены на WebView. При тестировании таких приложений требуется переключаться между “нативным” и “веб” контекстом.</p> <p>Теперь для переключения есть удобные методы:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Тут мы в "нативном" контексте</span> <span class="n">open</span><span class="o">();</span> <span class="err">$</span><span class="o">(</span><span class="n">accessibilityId</span><span class="o">(</span><span class="s">"URL input field"</span><span class="o">)).</span><span class="na">setValue</span><span class="o">(</span><span class="s">"www.google.com"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="n">accessibilityId</span><span class="o">(</span><span class="s">"Go To Site button"</span><span class="o">)).</span><span class="na">click</span><span class="o">();</span> <span class="c1">// Опа, и мы уже в "веб" контексте:</span> <span class="n">switchTo</span><span class="o">().</span><span class="na">context</span><span class="o">(</span><span class="s">"WEBVIEW_com.saucelabs.mydemoapp.rn"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#i-am-not-a-robot"</span><span class="o">).</span><span class="na">click</span><span class="o">();</span> <span class="n">assertThat</span><span class="o">(</span><span class="n">getContextHandles</span><span class="o">()).</span><span class="na">hasSize</span><span class="o">(</span><span class="mi">2</span><span class="o">)</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/pull/2308">PR 2308</a>.<br /> Спасибо <a href="https://github.com/amuthansakthivel">Amuthan Sakthivel</a> за <a href="https://github.com/selenide/selenide-appium/pull/149">PR 149</a>.</p> <p><br /></p> <h3 id="refactor-collection-conditions">Переколбас CollectionCondition</h3> <p>Мы поменяли внутреннее устройство условий для коллекций (класс <code class="language-plaintext highlighter-rouge">CollectionCondition</code>).</p> <p>Раньше, если вы хотели создать <a href="https://github.com/selenide/selenide/blob/main/src/test/java/integration/collections/CustomCollectionConditionTest.java">кастомную проверку для коллекций</a>, вы должны были реализовать метод <code class="language-plaintext highlighter-rouge">test(elements)</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">allTextsStartingWithZ</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">CollectionCondition</span><span class="o">()</span> <span class="o">{</span> <span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">test</span><span class="o">(</span><span class="nc">List</span><span class="o">&lt;</span><span class="nc">WebElement</span><span class="o">&gt;</span> <span class="n">webElements</span><span class="o">)</span> <span class="o">{</span> <span class="k">return</span> <span class="n">webElements</span><span class="o">.</span><span class="na">stream</span><span class="o">()</span> <span class="o">.</span><span class="na">map</span><span class="o">(</span><span class="n">webElement</span> <span class="o">-&gt;</span> <span class="n">webElement</span><span class="o">.</span><span class="na">getText</span><span class="o">().</span><span class="na">startsWith</span><span class="o">(</span><span class="s">"Z"</span><span class="o">))</span> <span class="o">.</span><span class="na">reduce</span><span class="o">(</span><span class="kc">true</span><span class="o">,</span> <span class="o">(</span><span class="n">x</span><span class="o">,</span> <span class="n">y</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="n">x</span> <span class="o">&amp;&amp;</span> <span class="n">y</span><span class="o">);</span> <span class="o">}</span> <span class="o">}</span> <span class="err">$$</span><span class="o">(</span><span class="s">".mudak"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">allTextsStartingWithZ</span><span class="o">)</span> </code></pre></div></div> <p>Этот метод останется ещё на какое-то время (для сохранения обратной совместимости), но <strong>рекомендуемый метод</strong> теперь будет <code class="language-plaintext highlighter-rouge">check(CollectionSource collection)</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">allTextsStartingWithZ</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">CollectionCondition</span><span class="o">()</span> <span class="o">{</span> <span class="kd">public</span> <span class="nc">CheckResult</span> <span class="nf">check</span><span class="o">(</span><span class="nc">CollectionSource</span> <span class="n">collection</span><span class="o">)</span> <span class="o">{</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">WebElement</span><span class="o">&gt;</span> <span class="n">elements</span> <span class="o">=</span> <span class="n">collection</span><span class="o">.</span><span class="na">getElements</span><span class="o">();</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="n">actualTexts</span> <span class="o">=</span> <span class="nc">ElementsCollection</span><span class="o">.</span><span class="na">texts</span><span class="o">(</span><span class="n">elements</span><span class="o">);</span> <span class="kt">boolean</span> <span class="n">allMatched</span> <span class="o">=</span> <span class="n">webElements</span><span class="o">.</span><span class="na">stream</span><span class="o">()</span> <span class="o">.</span><span class="na">map</span><span class="o">(</span><span class="n">webElement</span> <span class="o">-&gt;</span> <span class="n">webElement</span><span class="o">.</span><span class="na">getText</span><span class="o">().</span><span class="na">startsWith</span><span class="o">(</span><span class="s">"Z"</span><span class="o">))</span> <span class="o">.</span><span class="na">reduce</span><span class="o">(</span><span class="kc">true</span><span class="o">,</span> <span class="o">(</span><span class="n">x</span><span class="o">,</span> <span class="n">y</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="n">x</span> <span class="o">&amp;&amp;</span> <span class="n">y</span><span class="o">);</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">CheckResult</span><span class="o">(</span><span class="n">allMatched</span><span class="o">,</span> <span class="n">actualTexts</span><span class="o">);</span> <span class="o">}</span> <span class="o">}</span> <span class="err">$$</span><span class="o">(</span><span class="s">".mudak"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">allTextsStartingWithZ</span><span class="o">)</span> </code></pre></div></div> <h3 id="что-нам-это-даёт">Что нам это даёт?</h3> <p>В будущем это откроет нам возможности для улучшений проверок коллекций:</p> <ol> <li>Можно будет сильно ускорить проверки: например, быстро получить тексты всех элементов коллекции за один вызов JavaScript кода.</li> <li>В сообщении об ошибке писать не “актуальные тексты на момент составления сообщения”, а “актуальные тексты на момент последней проверки”. Как в <a href="/2021/09/28/selenide-5.25.0/#actual-value-at-the-moment-of-last-check">этой проблеме</a>, только с коллекциями.</li> </ol> <p>См. <a href="https://github.com/selenide/selenide/pull/2312">PR 2312</a> и <a href="https://github.com/selenide/selenide/pull/2307">PR 2307</a>.</p> <p><br /></p> <h3 id="news">Новости</h3> <ul> <li>Исторический момент: <a href="https://pikabu.ru/story/selenium_selenide_i_selenoid_8376039">первый мем про селенид</a></li> <li>Моё выступление на новогоднем девклубе: <a href="https://www.youtube.com/watch?v=jyPQzygMpoo&amp;ab_channel=DEVCLUB.EU">Думай как пиарщик</a></li> <li>Видос <a href="https://www.youtube.com/watch?v=M--_ziTZPQQ&amp;ab_channel=kanezi">Тестируем Spring с помощью Selenide</a> от kanezi</li> <li>Серия видосов на Testing Mini Bytes: <a href="https://www.youtube.com/watch?v=UQWQJ3dhgVI&amp;ab_channel=TestingMiniBytes">Selenide + Allure = Beautiful HTML Reports</a></li> <li>Пост <a href="https://creatingvalue.substack.com/p/why-we-chose-selenide-over-selenium">Why we chose Selenide over Selenium</a> от Amuthan Sakthivel</li> </ul> <center> <img src="/images/2023/05/selenide-meme.jpeg" width="600" alt="Selenide meme" /> </center> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2023/05/29/selenide-6.15.0/ http://ru.selenide.org/2023/05/29/selenide-6.15.0 2023-05-29T00:00:00+00:00 Вышла Selenide 6.14.0 <p>Привет!</p> <p>Пока не начался контрнаступ, давайте-ка обновимся на <a href="https://github.com/selenide/selenide/milestone/181?closed=1">Selenide 6.14.0</a> - а то потом будет не до него.</p> <p>В нём есть несколько изменений, которые как будто не очень большие, но могут чего-нибудь сломать. <em>Поэтому очень советую не оттягивать и <strong>обновиться сейчас</strong>.</em></p> <ul> <li><a href="#speedup-debug">Ускорили дебаг</a></li> <li><a href="#remove-flag--no-sandbox">Убрали флажок <code class="language-plaintext highlighter-rouge">--no-sandbox</code></a></li> <li><a href="#add-step-method">Добавили метод <code class="language-plaintext highlighter-rouge">step</code> для отчётиков</a></li> <li><a href="#drag-and-drop-with-options">Добавили метод <code class="language-plaintext highlighter-rouge">$.dragAndDrop(DragAndDropOptions)</code></a></li> <li><a href="#allow-negative-browser-position">Браузер за экран</a></li> <li><a href="#update-dependencies">Обновили зависимости</a></li> <li><a href="#news">Новости</a></li> <li><a href="#statistics">Статистика</a> <p><br /></p> </li> </ul> <h3 id="speedup-debug">Ускорили дебаг</h3> <p>Когда дебажишь свой тест и останавливаешься на брейкпойнте, иногда можно заметить, что IDE очень долго отображаешь значения полей в пэджобжекте. Вот в таком состоянии IDE может подвиснуть надолго:</p> <p><img src="/images/2023/05/selenide-debug.slow.png" alt="Selenide. debug. slow." width="600px" /></p> <p>Причина в том, что для отображения каждого поля Selenide обращается к вебдрайверу, чтобы получить имя тэга, актуальный текст и атрибуты элемента. Зато через некоторое время вы могли увидеть актуальную картинку:</p> <p><img src="/images/2023/05/selenide-debug.slow.result.png" alt="Selenide. debug. slow. result." width="600px" /></p> <p>Теперь этот процесс должен сильно ускориться. Селенид больше не будет обращаться к вебдрайверу, а просто покажет локатор элемента:</p> <p><img src="/images/2023/05/selenide-debug.fast.png" alt="Selenide. debug. slow. result." width="600px" /></p> <p>Но и формат метода <code class="language-plaintext highlighter-rouge">$.toString()</code> / <code class="language-plaintext highlighter-rouge">$$.toString()</code> тоже изменился. Будьте готовы.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2253">issue 2253</a>. и <a href="https://github.com/selenide/selenide/pull/2269">PR 2269</a>.</p> <blockquote> <p>Но не переживайте, это всё касается только дебага. При падении теста вы по-прежнему будете получать полную информацию об элементе с блекджектом и скриншотами. <br /></p> </blockquote> <h3 id="remove-flag--no-sandbox">Убрали флажок хрома <code class="language-plaintext highlighter-rouge">--no-sandbox</code></h3> <p>История с этим флажком мутная. Лично я не вижу никакой разницы, запускать хром с ним или без него.</p> <p>Но</p> <ol> <li>Некоторые пользователи говорят, что без флажка <code class="language-plaintext highlighter-rouge">--no-sandbox</code> хром не запускается в докере</li> <li>А другие пользователи говорят, что с флажком <code class="language-plaintext highlighter-rouge">--no-sandbox</code> процесс хрома остаётся висеть в фоне и пожирает весь CPU. Но это вроде только на винде (?)</li> </ol> <p>В общем, мы убрали этот флажок, потому что пользователям №1</p> <ul> <li>легко обнаружить проблему (хром тупо не запускается)</li> <li>легко добавить его самостоятельно: <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Configuration</span><span class="o">.</span><span class="na">browserCapabilities</span> <span class="o">=</span> <span class="k">new</span> <span class="nf">ChromeOptions</span><span class="o">().</span><span class="na">addArguments</span><span class="o">(</span><span class="s">"--no-sandbox"</span><span class="o">);</span> </code></pre></div> </div> </li> </ul> <p>См. <a href="https://github.com/selenide/selenide/issues/2270">issue 2270</a> и <a href="https://github.com/selenide/selenide/pull/2271">PR 2271</a>.</p> <p><br /></p> <h3 id="add-step-method">Добавили метод <code class="language-plaintext highlighter-rouge">step</code> для отчётиков</h3> <p>Если вы используете селенидовский встроенный отчёт (<code class="language-plaintext highlighter-rouge">TextReport</code>), то теперь можете группировать действия в “шаги” с помощью нового метода <code class="language-plaintext highlighter-rouge">step</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Test</span> <span class="kt">void</span> <span class="nf">authentication</span><span class="o">()</span> <span class="o">{</span> <span class="n">step</span><span class="o">(</span><span class="s">"login"</span><span class="o">,()-&gt;{</span> <span class="n">open</span><span class="o">(</span><span class="s">"/login.asp"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#username"</span><span class="o">).</span><span class="na">val</span><span class="o">(</span><span class="s">"u"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#password"</span><span class="o">).</span><span class="na">val</span><span class="o">(</span><span class="s">"p"</span><span class="o">);</span> <span class="o">});</span> <span class="n">step</span><span class="o">(</span><span class="s">"logout"</span><span class="o">,()-&gt;{</span> <span class="err">$</span><span class="o">(</span><span class="s">"#logout"</span><span class="o">).</span><span class="na">click</span><span class="o">();</span> <span class="err">$</span><span class="o">(</span><span class="s">"#goodBye"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Good bye looser!"</span><span class="o">));</span> <span class="o">});</span> <span class="o">}</span> </code></pre></div></div> <p>В отчёте шаги будут визуально выделяться.</p> <div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>+---------------+-----------------------------------------------+-------+------+ | Element |Subject |Status | ms. | +---------------+-----------------------------------------------+-------+------+ | login | |PASS | 4000 | | open | http://127.0.0.1:8080/my_account/account.html |PASS | 2662 | | #username | val "u" |PASS | 300 | | #password | val "p" |PASS | 400 | | logout | |PASS | 1023 | | #logout | click |PASS | 923 | | #goodBye | should have text "Good bye looser!" |PASS | 100 | +---------------+-----------------------------------------------+-------+------+ </code></pre></div></div> <p>Кстати, шаги могут быть вложенными друг в друга.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2172">issue 2172</a>. Спасибо <a href="https://github.com/Au6ojlut">Maksim @Au6ojlut</a> за <a href="https://github.com/selenide/selenide/pull/2250">PR 2250</a>.</p> <p><br /></p> <h3 id="drag-and-drop-with-options">Добавили метод <code class="language-plaintext highlighter-rouge">$.dragAndDrop(DragAndDropOptions)</code></h3> <p>Теперь метод <code class="language-plaintext highlighter-rouge">$.dragAndDrop</code> приобрёл более логичное звучание: сначала “что”, потом “куда” и наконец, “как”.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#drag1"</span><span class="o">).</span><span class="na">dragAndDrop</span><span class="o">(</span><span class="n">to</span><span class="o">(</span><span class="s">"#div2"</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">"#drag1"</span><span class="o">).</span><span class="na">dragAndDrop</span><span class="o">(</span><span class="n">to</span><span class="o">(</span><span class="s">"#div2"</span><span class="o">).</span><span class="na">usingJS</span><span class="o">());</span> </code></pre></div></div> <p>Спасибо <a href="https://github.com/Au6ojlut">Maksim @Au6ojlut</a> за <a href="https://github.com/selenide/selenide/pull/2245">PR 2245</a>.</p> <p><br /></p> <h3 id="allow-negative-browser-position">Разрешили двигать браузер за экран</h3> <p>Исправили мелкую багу, из-за которой нельзя было проставить негативные значения в позиции браузера:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Configuration</span><span class="o">.</span><span class="na">browserPosition</span> <span class="o">=</span> <span class="s">"-1900x-450"</span><span class="o">;</span> </code></pre></div></div> <p>Слабо себе представляю, зачем это может быть полезно, но исправили.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2258">issue 2258</a> и <a href="https://github.com/selenide/selenide/pull/2259">PR 2259</a>.</p> <p><br /></p> <h3 id="support-edge-binary-location">Путь к бинарнику Edge</h3> <p>В селениде есть настройка <code class="language-plaintext highlighter-rouge">Configuration.browserBinary</code>, позволяющая задать путь к бинарнику браузера. (на всякий случай: в большинстве случаев её <em>не нужно</em> задавать).</p> <p>Раньше эта настройка не поддерживалась для браузера Edge, а теперь поддерживается. Ура.</p> <p>Спасибо <a href="https://github.com/vlad8x8">Vladislav Velichko</a> за <a href="https://github.com/selenide/selenide/pull/2267">PR 2267</a>.</p> <p><br /></p> <h3 id="update-dependencies">Обновили зависимости</h3> <ul> <li><a href="https://github.com/selenide/selenide/pull/2277">Selenium 4.9.1</a> - см. <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">ченджлог</a></li> <li><a href="https://github.com/selenide/selenide/pull/2263">Netty 4.1.92.Final</a></li> </ul> <p><br /></p> <h3 id="news">Новости</h3> <ul> <li>Серия уроков <a href="https://www.youtube.com/playlist?list=PLFGzDEkV3ACu0i-Gd_whXsspqDlmP3ymP">Selenide Java with Cucumber</a> от <a href="https://www.youtube.com/@TechProEducationUS">TechPro Education</a></li> <li>Обзор <a href="https://www.youtube.com/watch?v=vUTQyr2UF0M&amp;ab_channel=OlehPendrak">Jetbrains Aqua для автоматизации тестирования</a> от <a href="https://www.youtube.com/@threadqa">Oleh Pendrak</a></li> </ul> <p><br /></p> <h3 id="statistics">Статистика</h3> <p>Количество ежемесячных скачиваний Селенида перевалило за 600 тыщ!</p> <center> <img src="/images/2023/04/selenide.downloads.jpg" width="800" /> </center> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2023/05/08/selenide-6.14.0/ http://ru.selenide.org/2023/05/08/selenide-6.14.0 2023-05-08T00:00:00+00:00 Вышла Selenide 6.13.0 <p>Привет!</p> <p>Сегодня у нас большой мажорный релиз <a href="https://github.com/selenide/selenide/milestone/177?closed=1">Selenide 6.13.0</a>.</p> <ul> <li><a href="#add-method-cached">Добавили метод <code class="language-plaintext highlighter-rouge">$.cached()</code></a></li> <li><a href="#mock-response-with-http-status">Добавили http статус при моке ответа сервера</a></li> <li><a href="#add-method-in-new-browser">Новый метод <code class="language-plaintext highlighter-rouge">inNewBrowser</code> для запуска куска кода в новом браузере</a></li> <li><a href="#add-method-doubleclick-with-options">Добавили метод <code class="language-plaintext highlighter-rouge">$.doubleClick(options)</code></a></li> <li><a href="#add-condition-inner-text">Добавили условие <code class="language-plaintext highlighter-rouge">$.shouldHave(innerText())</code></a></li> <li><a href="#add-condition-attributes">Добавили условие для коллекций <code class="language-plaintext highlighter-rouge">$$.shouldHave(attributes(...))</code></a></li> <li><a href="#clear-error-message-in-select">Ясное сообщение об ошибки в методах <code class="language-plaintext highlighter-rouge">$.select*()</code></a></li> <li><a href="#fix-method-sublist">Исправили ошибку в методе <code class="language-plaintext highlighter-rouge">$$.subList()</code></a></li> <li><a href="#update-dependencies">Обновили зависимости</a></li> <li><a href="#news">Новости</a> <p><br /></p> </li> </ul> <h3 id="add-method-cached">Добавили метод <code class="language-plaintext highlighter-rouge">$.cached()</code></h3> <p>Иногда приходится воротить довольно сложный код для поиска элемента. И он может работать <strong>медленно</strong>, особенно если элемент ищется из какой-то большой коллекции с применением сложной фильтрации. Что-то вроде такого:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">ElementsCollection</span> <span class="n">subscriptions</span> <span class="o">=</span> <span class="err">$$</span><span class="o">(</span><span class="s">"div.subs-expands"</span><span class="o">)</span> <span class="o">.</span><span class="na">filter</span><span class="o">(</span><span class="n">childExactText</span><span class="o">(</span> <span class="nc">By</span><span class="o">.</span><span class="na">xpath</span><span class="o">(</span><span class="s">".//div[contains(@class,'data')]//div[contains(@class,'heading')]"</span><span class="o">),</span> <span class="n">orderNumber</span><span class="o">)</span> <span class="o">);</span> <span class="nc">SelenideElement</span> <span class="n">target</span> <span class="o">=</span> <span class="n">subscriptions</span> <span class="o">.</span><span class="na">filter</span><span class="o">(</span><span class="n">childAttributeValue</span><span class="o">(...))</span> <span class="o">.</span><span class="na">find</span><span class="o">(</span><span class="n">childExactText</span><span class="o">(....));</span> </code></pre></div></div> <p>Каждое обращение к <code class="language-plaintext highlighter-rouge">target</code> заметно притормаживает.</p> <p>Теперь такие тесты можно ускорить, закэшировав значение <code class="language-plaintext highlighter-rouge">target</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">SelenideElement</span> <span class="n">target</span> <span class="o">=</span> <span class="n">subscriptions</span> <span class="o">.</span><span class="na">filter</span><span class="o">(..)</span> <span class="o">.</span><span class="na">find</span><span class="o">(..)</span> <span class="o">.</span><span class="na">cached</span><span class="o">();</span> </code></pre></div></div> <p>Естественно, это можно сделать только в том случае, если вы уверены, что этот элемент не меняется, не перегружается и т.д.<br /> Если он всё-таки перегрузится, то вы словите тот самый легендарный <code class="language-plaintext highlighter-rouge">StaleElementReferenceException</code>.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2171">issue 2171</a>, <a href="https://github.com/selenide/selenide/issues/1927">issue 1927</a> и <a href="https://github.com/selenide/selenide/pull/2189">PR 2189</a>.</p> <p><br /></p> <h3 id="mock-response-with-http-status">Добавили http статус при моке ответа сервера</h3> <p>В селениде есть методы, чтобы замокать ответ сервера:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">getSelenideProxy</span><span class="o">().</span><span class="na">responseMocker</span><span class="o">().</span><span class="na">mockText</span><span class="o">(</span><span class="s">"login-mock"</span><span class="o">,</span> <span class="n">urlContains</span><span class="o">(</span><span class="no">POST</span><span class="o">,</span> <span class="s">"/login"</span><span class="o">),</span> <span class="o">()</span> <span class="o">-&gt;</span> <span class="s">"{role: admin}"</span><span class="o">);</span> </code></pre></div></div> <p>Раньше можно было мокать только тело ответа, но статус всегда оставался 200 (“OK”).<br /> Теперь можно задать и другой статус:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">getSelenideProxy</span><span class="o">().</span><span class="na">responseMocker</span><span class="o">().</span><span class="na">mockText</span><span class="o">(</span><span class="s">"login-mock"</span><span class="o">,</span> <span class="n">urlContains</span><span class="o">(</span><span class="no">POST</span><span class="o">,</span> <span class="s">"/login"</span><span class="o">),</span> <span class="mi">403</span><span class="o">,</span> <span class="o">()</span> <span class="o">-&gt;</span> <span class="s">"{role: looser}"</span><span class="o">);</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2227">issue 2227</a> и <a href="https://github.com/selenide/selenide/pull/2234">PR 2234</a>.</p> <p><br /></p> <h3 id="add-method-in-new-browser">Новый метод <code class="language-plaintext highlighter-rouge">inNewBrowser</code> для запуска куска кода в новом браузере</h3> <p>Иногда вам хочется посреди теста запустить кусок кода в новом браузере.</p> <blockquote> <p>Если что, я это осуждаю: такие вспомогательные действия надо делать не через UI (который мы тестируем, а потому не доверяем), а каким-то контролируем способом: через API, прямой запрос в базу и т.п.</p> </blockquote> <p>Уже давно для этого есть <a href="/2019/10/16/selenide-5.4.0/#add-method-using">метод <code class="language-plaintext highlighter-rouge">using</code></a>. Но он требует, чтобы вы открыли новый браузер с какими-то своими настройками. А что, если вам подходят обычные селенидовские настройки? То есть вам нужен точно такой же браузер, только новый?</p> <p>Теперь для этого есть метод <code class="language-plaintext highlighter-rouge">inNewBrowser</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">open</span><span class="o">(</span><span class="s">"https://site.com/login/as/user/bob"</span><span class="o">);</span> <span class="n">inNewBrowser</span><span class="o">(()</span> <span class="o">-&gt;</span> <span class="o">{</span> <span class="n">open</span><span class="o">(</span><span class="s">"https://site.com/login/as/admin"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="n">by</span><span class="o">(</span><span class="s">"value"</span><span class="o">,</span> <span class="s">"bob"</span><span class="o">)).</span><span class="na">find</span><span class="o">(</span><span class="s">"[name=is_admin]"</span><span class="o">).</span><span class="na">setEnabled</span><span class="o">();</span> <span class="o">});</span> <span class="err">$</span><span class="o">(</span><span class="s">"h1"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Hello, chat admin!"</span><span class="o">));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2213">issue 2213</a> и <a href="https://github.com/selenide/selenide/pull/2236">PR 2236</a>.</p> <p><br /></p> <h3 id="add-method-doubleclick-with-options">Добавили метод <code class="language-plaintext highlighter-rouge">$.doubleClick(options)</code></h3> <p>Раньше был просто метод <code class="language-plaintext highlighter-rouge">$.doubleClick()</code>, который мог кликать только по центру элемента. Теперь же у него появился продвинутый тёзка с параметром <code class="language-plaintext highlighter-rouge">options</code>. Опции такие же, как и у обычного клика:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">".btn"</span><span class="o">).</span><span class="na">doubleClick</span><span class="o">(</span><span class="n">usingDefaultMethod</span><span class="o">());</span> <span class="err">$</span><span class="o">(</span><span class="s">".btn"</span><span class="o">).</span><span class="na">doubleClick</span><span class="o">(</span><span class="n">usingJavaScript</span><span class="o">());</span> <span class="err">$</span><span class="o">(</span><span class="s">".btn"</span><span class="o">).</span><span class="na">doubleClick</span><span class="o">(</span><span class="n">usingDefaultMethod</span><span class="o">().</span><span class="na">offset</span><span class="o">(</span><span class="mi">66</span><span class="o">,</span> <span class="mi">33</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">".btn"</span><span class="o">).</span><span class="na">doubleClick</span><span class="o">(</span><span class="n">usingJavaScript</span><span class="o">().</span><span class="na">offset</span><span class="o">(</span><span class="mi">66</span><span class="o">,</span> <span class="mi">33</span><span class="o">).</span><span class="na">withTimeout</span><span class="o">(</span><span class="n">ofSeconds</span><span class="o">(</span><span class="mi">9</span><span class="o">)));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2133">issue 2133</a>. Спасибо <a href="https://github.com/aakachurin">aakachurin</a> за <a href="https://github.com/selenide/selenide/pull/2135">PR 2135</a>.</p> <p><br /></p> <h3 id="add-condition-inner-text">Добавили условие <code class="language-plaintext highlighter-rouge">$.shouldHave(innerText())</code></h3> <p>Оно позволит проверять текст невидимых элементов.</p> <blockquote> <p>Скорее всего это плохая идея: раз пользователь не видит элемента, значит, и проверять его не надо.</p> </blockquote> <p>Но если всё-таки очень хочется, то можно:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#theHiddenElement"</span><span class="o">)</span> <span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">innerText</span><span class="o">(</span><span class="s">"Видишь суслика? И я не вижу. А он есть!"</span><span class="o">));</span> <span class="c1">// Обычный $("#theHiddenElement").text() выдаёт здесь пустую строку "";</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2220">issue 2220</a> и <a href="https://github.com/selenide/selenide/pull/2223">PR 2223</a>.</p> <p><br /></p> <h3 id="add-condition-attributes">Добавили условие для коллекций <code class="language-plaintext highlighter-rouge">$$.shouldHave(attributes(...))</code></h3> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$$</span><span class="o">(</span><span class="s">"#numbers option"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">attributes</span><span class="o">(</span><span class="s">"value"</span><span class="o">,</span> <span class="s">"one"</span><span class="o">,</span> <span class="s">"two"</span><span class="o">,</span> <span class="s">"three"</span><span class="o">,</span> <span class="s">"four"</span><span class="o">,</span> <span class="s">"five"</span><span class="o">));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2091">issue 2091</a>. Спасибо <a href="https://github.com/AlexLAA">Alexey Lakovych</a> за <a href="https://github.com/selenide/selenide/pull/2091">PR 2091</a>. Также см. <a href="https://github.com/selenide/selenide/pull/2230">PR 2230</a>.</p> <p><br /></p> <h3 id="clear-error-message-in-select">Ясное сообщение об ошибки в методах <code class="language-plaintext highlighter-rouge">$.select*()</code></h3> <p>В селениде есть методы для работы с выпадающими списками:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"select#gender"</span><span class="o">).</span><span class="na">selectOptionContainingText</span><span class="o">(</span><span class="s">"Female"</span><span class="o">);</span> </code></pre></div></div> <p>Недавно мы <a href="/2022/11/21/selenide-6.10.0/#select-options-using-javascript">переделали их реализацию на JavaScript</a> - так быстрее и надёжнее.</p> <p>Но оказалось, что если по ошибке вызвать такой метода для не-селекта, вылетала очень непонятная ошибка:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"ul"</span><span class="o">).</span><span class="na">selectOptionContainingText</span><span class="o">(</span><span class="s">"Kelly Snyder"</span><span class="o">);</span> <span class="o">--&gt;</span> <span class="nl">JavascriptException:</span> <span class="n">javascript</span> <span class="nl">error:</span> <span class="n">undefined</span> <span class="n">is</span> <span class="n">not</span> <span class="nf">iterable</span> <span class="o">(</span><span class="n">cannot</span> <span class="n">read</span> <span class="n">property</span> <span class="nf">Symbol</span><span class="o">(</span><span class="nc">Symbol</span><span class="o">.</span><span class="na">iterator</span><span class="o">))</span> </code></pre></div></div> <p>Теперь сообщение будет понятное:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">IllegalArgumentException:</span> <span class="nc">Cannot</span> <span class="n">select</span> <span class="n">option</span> <span class="n">from</span> <span class="n">a</span> <span class="n">non</span><span class="o">-</span><span class="n">select</span> <span class="n">element</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2231">issue 2231</a> и <a href="https://github.com/selenide/selenide/pull/2233">PR 2233</a>.</p> <h3 id="fix-method-sublist">Исправили ошибку в методе <code class="language-plaintext highlighter-rouge">$$.subList()</code></h3> <p>Как вы знаете, в селениде есть удобные методы для проверки разом целой коллекции элементов:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$$</span><span class="o">(</span><span class="s">"#numbers"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">texts</span><span class="o">(</span><span class="s">"One"</span><span class="o">,</span> <span class="s">"Two"</span><span class="o">,</span> <span class="s">"Three"</span><span class="o">,</span> <span class="s">"Four"</span><span class="o">,</span> <span class="s">"Five"</span><span class="o">));</span> </code></pre></div></div> <p>Но метод <code class="language-plaintext highlighter-rouge">$$</code> возвращает объект <code class="language-plaintext highlighter-rouge">ElementsCollection</code>, который, к сожалению, наследуется от <code class="language-plaintext highlighter-rouge">AbstractList&lt;SelenideElement&gt;</code>. А потому случайно (так не задумывалось!) наследует от него некоторые методы, на которые мы не рассчитывали.</p> <p>Один из таких методов - <code class="language-plaintext highlighter-rouge">subList</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$$</span><span class="o">(</span><span class="s">".user"</span><span class="o">).</span><span class="na">subList</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="mi">4</span><span class="o">).</span><span class="na">iterator</span><span class="o">();</span> </code></pre></div></div> <p>Приведённый выше итератор возвращает не три, а всего два элемента. Обрезает последний. Ошибочка. <code class="language-plaintext highlighter-rouge">¯\_(ツ)_/¯</code></p> <p>Теперь она оперативно исправлена.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2239">issue 2239</a> и <a href="https://github.com/selenide/selenide/pull/2240">PR 2240</a>.</p> <p><br /></p> <h3 id="update-dependencies">Обновили зависимости</h3> <ul> <li>bump Selenium from 4.8.1 to 4.8.3 – см. <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">CHANGELOG</a></li> <li>bump LittleProxy from 2.0.16 to 2.0.17</li> <li>bump BrowserUpProxy from 2.2.8 to 2.2.9</li> <li>bump nettyVersion from 4.1.90.Final to 4.1.91.Final</li> </ul> <p><br /></p> <h3 id="news">Новости</h3> <p>Сегодня у нас подборка видосов про Селенид</p> <ul> <li>на русском: <a href="https://youtu.be/k0A8HFWV_iE">ChatGPT: Как скачать файл в Selenide</a></li> <li>на английском: <a href="https://www.youtube.com/watch?v=GwHG550moGc">ChatGPT: How to download file in Selenide</a></li> <li><a href="https://www.youtube.com/watch?v=18J2_4a4Cl4&amp;ab_channel=Jfokus">Flaky tests на английском</a></li> <li><a href="https://www.youtube.com/watch?v=SohZfPKicZQ&amp;ab_channel=OlehPendrak">Ускоряем UI Автотесты с помощью подстановки Cookies</a> by Oleh Pendrak</li> <li><a href="https://www.youtube.com/watch?v=wN45Qla66-o&amp;list=PLFGoYjJG_fqrvWt1FfHqKoREQmSPxazBq&amp;ab_channel=NaveenAutomationLabs">Канал про селенид</a> от NaveenAutomationLabs</li> <li><a href="https://www.youtube.com/watch?v=9S6xaAvJc9M&amp;t=4226s&amp;ab_channel=HillelITSchool">Selenide: як тестувати веб-елементи</a></li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2023/04/04/selenide-6.13.0/ http://ru.selenide.org/2023/04/04/selenide-6.13.0 2023-04-04T00:00:00+00:00 Вышла Selenide 6.13.0 <p>Всем привет!</p> <p>Ура, сегодня у нас новый релиз <strong>Selenide 6.13.0</strong></p> <ul> <li><a href="#banners-support">Поддержка баннеров</a></li> <li><a href="#news">Новости</a> <p><br /></p> </li> </ul> <h3 id="banners-support">Поддержка баннеров</h3> <h4 id="проблема">Проблема</h4> <p>Очень часто люди спрашивают: “А что делать, если посреди теста на экране может выскочить баннер или какой-то ещё неожиданный элемент?”</p> <p>Ведь он может перекрыть другие элементы, закрыть важную кнопку и т.п. - и таким образом сломать тест.</p> <blockquote> <p><a href="https://ru.selenide.org/2019/12/02/advent-calendar-how-to-abuse-selenide/">Я всегда на это люто ругался</a> и настоятельно советовал взять тестовую среду под контроль и самому из теста регулировать, когда баннеры должны появляться, а когда нет.</p> </blockquote> <p>Алексей Виноградов сделал выступление на эту тему: <a href="https://www.youtube.com/watch?v=MLxf9q9qXu4&amp;ab_channel=%D0%A2%D0%B5%D1%85%D0%BD%D0%BE%D0%BB%D0%BE%D0%B3%D0%B8%D0%B8%D0%B2%D0%9A%D0%BE%D0%BD%D1%82%D1%83%D1%80%D0%B5">Spinner-driven-development</a>.</p> <p><br /></p> <h4 id="стадия-принятия">Стадия принятия</h4> <p>Но слишком уж это распространённая проблема. В конце концов, Селенид задуман для того, чтобы помогать людям решать проблемы, а не читать нотации.</p> <p>Мы решили пойти людям навстречу и создать решение для проблемы баннеров. Теперь в начале теста вы можете вызвать метод <code class="language-plaintext highlighter-rouge">Selenide.onBanner()</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">onBanner</span><span class="o">(</span><span class="s">"#pizzaAds"</span><span class="o">,</span> <span class="no">CLOSE</span><span class="o">,</span> <span class="s">".btn-close"</span><span class="o">);</span> </code></pre></div></div> <p><br /></p> <h4 id="как-это-работает">Как это работает</h4> <p>По умолчанию, этот метод добавит вебдрайверу листенер, который будет перед каждым кликом или проверкой проверять, не появился ли элемент с данным селектором <code class="language-plaintext highlighter-rouge">"#pizzaAds"</code>. Если появился, селенид попытается закрыть его, нажав на кнопку закрытия <code class="language-plaintext highlighter-rouge">".btn-close"</code>.</p> <p>Этот метод называется <code class="language-plaintext highlighter-rouge">POLL</code>. Он самый простой и надёжный, но и самый медленный. Ведь селенид должен будет кучу раз спрашивать у браузера, не появился ли баннер. Каждый такой запрос занимает некоторое время.</p> <p><br /></p> <h4 id="альтернативные-методы">Альтернативные методы</h4> <p>Поэтому мы добавили ещё два альтернативных метода, которыми селенид может проверять, а не появился ли баннер. Их можно включить либо глобально настройкой:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Configuration</span><span class="o">.</span><span class="na">bannerCloseMode</span> <span class="o">=</span> <span class="no">POLL</span><span class="o">;</span> <span class="c1">// по умолчанию</span> <span class="c1">// Слушает события по изменению DOM через CDP:</span> <span class="nc">Configuration</span><span class="o">.</span><span class="na">bannerCloseMode</span> <span class="o">=</span> <span class="no">CDP</span><span class="o">;</span> <span class="c1">// Работает только в Chromium-браузерах</span> <span class="c1">// Скармливает html текущей страницы ChatGPT и спрашивает, нет ли там баннера:</span> <span class="nc">Configuration</span><span class="o">.</span><span class="na">bannerCloseMode</span> <span class="o">=</span> <span class="no">CHATGPT</span><span class="o">;</span> </code></pre></div></div> <p>Либо вы можете задать его параметром с помощью <code class="language-plaintext highlighter-rouge">using</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">onBanner</span><span class="o">(</span><span class="n">using</span><span class="o">(</span><span class="no">CDP</span><span class="o">)</span> <span class="o">.</span><span class="na">withBannerSelector</span><span class="o">(</span><span class="s">"#pizzaAds"</span><span class="o">)</span> <span class="o">.</span><span class="na">withCloseButtonSelector</span><span class="o">(</span><span class="s">".btn-close"</span><span class="o">)</span> <span class="o">.</span><span class="na">withAction</span><span class="o">(</span><span class="no">CLOSE</span><span class="o">)</span> <span class="o">);</span> </code></pre></div></div> <h4 id="кастомный-обработчик">Кастомный обработчик</h4> <p>Есть также более общий вариант, в котором вы сможете залямбдашить свою специфическую логику обработки баннера. Вы же не всегда хотите сразу закрыть баннер - иногда сначала нужно из него прочитать какую-то информацию.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">onBanner</span><span class="o">(</span><span class="n">using</span><span class="o">(</span><span class="no">CHATGPT</span><span class="o">)</span> <span class="o">.</span><span class="na">withBannerSelector</span><span class="o">(</span><span class="s">"#pizzaAds"</span><span class="o">)</span> <span class="o">.</span><span class="na">withCloseButtonSelector</span><span class="o">(</span><span class="s">".btn-close"</span><span class="o">)</span> <span class="o">.</span><span class="na">withAction</span><span class="o">((</span><span class="n">banner</span><span class="o">,</span> <span class="n">closeButton</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="o">{</span> <span class="n">banner</span><span class="o">.</span><span class="na">find</span><span class="o">(</span><span class="s">".title"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Ваш пароль изменён."</span><span class="o">));</span> <span class="nc">String</span> <span class="n">newPassword</span> <span class="o">=</span> <span class="n">banner</span><span class="o">.</span><span class="na">find</span><span class="o">(</span><span class="s">".new-password"</span><span class="o">).</span><span class="na">text</span><span class="o">();</span> <span class="n">closeButton</span><span class="o">.</span><span class="na">doubleClick</span><span class="o">();</span> <span class="o">})</span> <span class="o">);</span> </code></pre></div></div> <p><br /></p> <p>Пробуйте, пишите, заводите тикеты на гитхабе. Предлагайте свои алгоритмы для обнаружения баннеров.</p> <p><em>Хватит примерять на себя белые пальто и ссориться из-за дурацких принципов.</em></p> <blockquote> <p>Давайте объединимся против баннеров!</p> </blockquote> <h3 id="news">News</h3> <p>Сегодня у нас три видоса про Селенид</p> <ul> <li>на русском: <a href="https://youtu.be/k0A8HFWV_iE">ChatGPT: Как скачать файл в Selenide</a></li> <li>на английском: <a href="https://www.youtube.com/watch?v=GwHG550moGc">ChatGPT: How to download file in Selenide</a></li> <li><a href="https://www.youtube.com/watch?v=SohZfPKicZQ&amp;ab_channel=OlehPendrak">Ускоряем UI Автотесты с помощью подстановки Cookies</a> by Oleh Pendrak</li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2023/04/01/selenide-6.13.0/ http://ru.selenide.org/2023/04/01/selenide-6.13.0 2023-04-01T00:00:00+00:00 Вышла Selenide 6.12.4 <p>Привет!</p> <p>А вы следили за новостями 23 марта? Молодцы!</p> <p>Сегодня у нас <em>Точка Отсчёта</em> - релиз <a href="https://github.com/selenide/selenide/milestone/180?closed=1">Selenide 6.12.4</a>.</p> <ul> <li><a href="#workaround-for-chromedriver-bug">Костыль для Хрома</a></li> <li><a href="#support-jdk-http-client">Добавили поддержку jdk-http-client</a></li> <li><a href="#restore-proxy-after-using">Исправили $.download(PROXY) после “using”</a></li> <li><a href="#fix-clear-when-element-disappears">Исправили $.clear() при пропадании элемента</a></li> <li><a href="#update-dependencies">Обновили зависимости</a></li> <li><a href="#release-selenide-appium">Выпустили selenide-appium 2.7.0</a></li> <li><a href="#release-selenide-selenoid">Выпустили selenide-selenoid 2.3.6</a></li> <li><a href="#news">Новости</a> <p><br /></p> </li> </ul> <h3 id="workaround-for-chromedriver-bug">Костыль для Хрома</h3> <p>Напоминание: если вы всё ещё роете интернет в поисках лекарства против</p> <blockquote> <p>Invalid Status code=403 text=Forbidden</p> </blockquote> <p>то лекарство уже было выпущено в <a href="/2023/03/09/selenide-6.12.2/">Selenide 6.12.2</a>.</p> <p><br /></p> <h3 id="support-jdk-http-client">Добавили поддержку <code class="language-plaintext highlighter-rouge">jdk-http-client</code> вместо <code class="language-plaintext highlighter-rouge">netty-client</code></h3> <p>По умолчанию по-прежнему используется <code class="language-plaintext highlighter-rouge">netty-client</code>, но если вы хотите <a href="https://www.selenium.dev/blog/2022/using-java11-httpclient/">перейти на jdk-http-client</a>, то можете это легко сделать:</p> <ol> <li>Добавить зависимость <br /> <code class="language-plaintext highlighter-rouge">org.seleniumhq.selenium:selenium-http-jdk-client:$seleniumVersion</code></li> <li>Добавить пропертю перед открытием браузера: <br /> <code class="language-plaintext highlighter-rouge">System.setProperty("webdriver.http.factory", "jdk-http-client");</code></li> </ol> <p>См. <a href="https://github.com/selenide/selenide/issues/2215">issue 2215</a> и <a href="https://github.com/selenide/selenide/pull/2216">PR 2216</a>.</p> <p><br /></p> <h3 id="restore-proxy-after-using">Исправили работу прокси после метода <code class="language-plaintext highlighter-rouge">using</code></h3> <p>Это почти такая же проблема, как в <a href="https://github.com/selenide/selenide/issues/2202">issue 2202</a>, но только с прокси.</p> <p>В общем, стоило вам разочек использовать метод <code class="language-plaintext highlighter-rouge">using</code>, как у вас сразу пропадал прокси. И дальнейшее скачивание файлов (или для чего ещё вы использовали прокси) больше не работало.</p> <p>Но судя по всему, про этот <a href="/2019/10/16/selenide-5.4.0/#add-method-using">супер-удобный метод <code class="language-plaintext highlighter-rouge">using</code></a> мало кто знает, потому что жалоба была всего одна. :)</p> <p>Ну вот, теперь и <code class="language-plaintext highlighter-rouge">using</code> починили, и про него узнает больше народу. :)</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2208">PR 2208</a> и <a href="https://github.com/selenide/selenide/pull/2209">PR 2209</a>.</p> <p><br /></p> <h3 id="fix-clear-when-element-disappears">Исправили <code class="language-plaintext highlighter-rouge">$.clear()</code> при пропадании элемента</h3> <p>Как вы знаете, в селениде есть метод <code class="language-plaintext highlighter-rouge">$("input").clear()</code>, который очищает поле ввода. Оказалось, что метод мог упасть в одной редкой ситуации. А именно, если в результате очистки элемент пропадает. В этот момент метод <code class="language-plaintext highlighter-rouge">$.clear()</code> пытался сгенерировать событие <code class="language-plaintext highlighter-rouge">on change</code> на этом элементе - и падал.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2207">issue 2207</a> и <a href="https://github.com/selenide/selenide/pull/2221">PR 2221</a>.</p> <p><br /></p> <h3 id="update-dependencies">Обновили зависимости</h3> <ul> <li>#2210 Bump nettyVersion from 4.1.89.Final to 4.1.90.Final</li> <li>#2218 Bump slf4jVersion from 2.0.6 to 2.0.7</li> </ul> <p><br /></p> <h3 id="release-selenide-appium">Выпустили <code class="language-plaintext highlighter-rouge">selenide-appium:2.7.0</code></h3> <ul> <li>Добавили скролл вверх-вниз для мобильников (#139)</li> <li>Исправили функцию <code class="language-plaintext highlighter-rouge">terminateApp</code> (#146)</li> <li>Обновились на Selenide 6.12.4 (#143)</li> </ul> <p>См. <a href="https://github.com/selenide/selenide-appium/releases/tag/v2.7.0">release notes</a>.</p> <p><br /></p> <h3 id="release-selenide-selenoid">Выпустили <code class="language-plaintext highlighter-rouge">selenide-selenoid:2.3.6</code></h3> <ul> <li>Обновились на Selenide 6.12.4</li> </ul> <p>См. <a href="https://github.com/selenide/selenide-selenoid/releases/tag/v2.3.6">release notes</a>.</p> <p><br /></p> <h3 id="news">News</h3> <ul> <li>Я запилил первый видос после 9-летнего перерыва :) <a href="https://youtu.be/k0A8HFWV_iE">Как скачать файл в Selenide: спросим у ChatGPT</a></li> <li>Наконец-то у меня появился <a href="https://www.youtube.com/watch?v=18J2_4a4Cl4&amp;ab_channel=Jfokus">доклад про Flaky tests на английском</a> - конференция JFokus, Стокгольм, 8.02.2023</li> <li>Видос <a href="https://www.youtube.com/watch?v=9S6xaAvJc9M&amp;t=4226s&amp;ab_channel=HillelITSchool">Selenide: як тестувати веб-елементи</a> от Hillel IT School</li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2023/03/23/selenide-6.12.4/ http://ru.selenide.org/2023/03/23/selenide-6.12.4 2023-03-23T00:00:00+00:00 Вышла Selenide 6.12.2 <p>Привет!</p> <p>Срочно обновляйтесь на <a href="https://github.com/selenide/selenide/milestone/178?closed=1">Selenide 6.12.2</a>.</p> <p>Он содержит один важный костыль для баги в Chromedriver 111.</p> <blockquote> <p>Invalid Status code=403 text=Forbidden</p> </blockquote> <h3 id="в-чём-проблема">В чём проблема?</h3> <p>Недавно вышла новая версия Chrome и Chromedriver 111. И у всех, кто на неё обновился, резко посыпались тесты. Браузер открывался, но при этом тест получал от вебдрайвера ошибку и дальше не мог ничего сделать, в том числе закрыть этот самый браузер.</p> <p>В логах было видно такое вот красноречивое сообщение:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Starting</span> <span class="nc">ChromeDriver</span> <span class="mf">111.0</span><span class="o">.</span><span class="mf">5563.64</span> <span class="n">on</span> <span class="n">port</span> <span class="mi">31021</span> <span class="n">org</span><span class="o">.</span><span class="na">openqa</span><span class="o">.</span><span class="na">selenium</span><span class="o">.</span><span class="na">remote</span><span class="o">.</span><span class="na">http</span><span class="o">.</span><span class="na">WebSocket</span><span class="n">$Listener</span> <span class="n">onError</span> <span class="nl">WARNING:</span> <span class="nc">Invalid</span> <span class="nc">Status</span> <span class="n">code</span><span class="o">=</span><span class="mi">403</span> <span class="n">text</span><span class="o">=</span><span class="nc">Forbidden</span> <span class="n">java</span><span class="o">.</span><span class="na">io</span><span class="o">.</span><span class="na">IOException</span><span class="o">:</span> <span class="nc">Invalid</span> <span class="nc">Status</span> <span class="n">code</span><span class="o">=</span><span class="mi">403</span> <span class="n">text</span><span class="o">=</span><span class="nc">Forbidden</span> <span class="o">...</span> </code></pre></div></div> <p>И хотя это <a href="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4361">бага хромдрайвера</a>, для неё нашёлся один простой костыль, и мы его по-быстрому запилили в Селениде.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2192">issue 2192</a> и <a href="https://github.com/selenide/selenide/pull/2194">PR 2194</a>.</p> <blockquote> <p>А вообще, обновляйтесь на <a href="/2023/03/22/selenide-6.12.4/#support-jdk-http-client">HttpClient</a>. Он требует Java11+, но зато таких багов там не будет.</p> </blockquote> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2023/03/09/selenide-6.12.2/ http://ru.selenide.org/2023/03/09/selenide-6.12.2 2023-03-09T00:00:00+00:00 Вышла Selenide 6.12.0 <p>Привет!</p> <p>В этот трагичный и одновременно праздничный день мы выпустили релиз <a href="https://github.com/selenide/selenide/milestone/173?closed=1">Selenide 6.12.0</a>.</p> <p>В нём почти нет фич, но есть новый режим, который может сильно повлиять на ваши тесты.</p> <ul class="blogpost-menu"> <li><a href="#new-headless-mode">Новый безбашенный режим</a></li> <li><a href="#improve-logs-when-downloading-file">Улучшили логирование при скачивании файлов</a></li> <li><a href="#improve-download-in-edge">Улучшили скачивание файлов в Edge под Windows</a></li> <li><a href="#update-dependencies">Обновили зависимости</a></li> <li><a href="#rename-master-to-main">Переименовали master в main</a></li> </ul> <p><br /></p> <h3 id="new-headless-mode">Новый безбашенный режим</h3> <p>В Chromium-браузерах появился новый безголовый (headless) режим. Подробнее о нём <a href="https://developer.chrome.com/articles/new-headless/">в их блоге</a>.</p> <p>Если вкратце, этот новый режим внутри использует тот же код, что и обычный headful, и поэтому должен вылечить все болячки headless режима. А вот старый headless режим по сути был отдельным браузером со своими особенностями и багами.</p> <p>В теории вы всё ещё можете переключаться между старым и новым headless режимом. Но на практике вам придётся переключиться на новый, т.к. при обновлении Chrome и Edge перестало работать скачивание файлов в старом headless режиме.</p> <p>В общем, в Selenide 6.12.0 новый headless режим будет включаться по умолчанию.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2104">issue 2104</a>. Спасибо <a href="https://github.com/BorisOsipov">Boris Osipov</a> за <a href="https://github.com/selenide/selenide/pull/2105">PR 2105</a> и <a href="https://github.com/selenide/selenide/pull/2169">PR 2169</a>.</p> <p><br /></p> <h3 id="improve-logs-when-downloading-file">Улучшили логирование при скачивании файлов</h3> <p>Если скачивание файла падает (особенно методом <code class="language-plaintext highlighter-rouge">FOLDER</code>), иногда бывает сложно понять, почему именно. Мы немного доработали логирование внутри метода <code class="language-plaintext highlighter-rouge">$.download()</code>, так что теперь должно стать полегче.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2167">PR 2167</a>.</p> <p><br /></p> <h3 id="improve-download-in-edge">Улучшили скачивание файлов в Edge под Windows</h3> <p>До сих пор селенид отслеживал только временные файлы “<em>.crdownload”, которые хромиум использует при скачивании файлов. Но оказалось, что на Windows браузер Edge создаёт ещё и временные файлы “</em>.tmp”. Теперь селенид отслеживает и их.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2167">PR 2167</a>.</p> <p><br /></p> <h3 id="update-dependencies">Обновили зависимости</h3> <ul> <li>bump Selenium from 4.8.0 to 4.8.1, см. <a href="https://github.com/selenide/selenide/pull/2161">PR 2161</a> и <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">ченджлог Selenium</a>.</li> <li>Bump nettyVersion from 4.1.87.Final to 4.1.89.Final, см. <a href="https://github.com/selenide/selenide/pull/2158">PR 2158</a>.</li> </ul> <p><br /></p> <h3 id="rename-master-to-main">Переименовали ветку <code class="language-plaintext highlighter-rouge">master</code> в <code class="language-plaintext highlighter-rouge">main</code></h3> <p>Да-да, это отголоски того самого BLM. Один умный человек убедил меня, что стоит это сделать. :)</p> <p><br /></p> <h3 id="news">News</h3> <ul> <li>Пост <a href="https://oleksandr-podoliako.medium.com/test-automation-framework-for-ui-testing-with-java-fddd1e3fd75b">Test automation framework for UI testing with java</a> by Oleksandr Podoliako</li> <li>Пост <a href="https://pradappandiyan.medium.com/running-test-automation-with-selenide-on-gitlab-fb13c0a0dddf">Running test automation with Selenide on GitLab</a> by Pradap Pandiyan</li> <li>Моё видео с Continuous Testing Meetup: <a href="https://www.youtube.com/watch?v=5qiuRoUcICs&amp;t=48m02s">Selenide UI tests in java</a>, 23.01.2023</li> <li>Видео <a href="https://www.youtube.com/watch?v=G7iYLr_IgGA&amp;ab_channel=FullStackQA">Автотесты с нуля для начинающих Java + Selenide + TestNG + Maven</a> на канале FullStackQA</li> </ul> <p><br /> Ну а почему же я назвал этот день праздничным? Да потому, что 24 февраля вообще-то День Независимости Эстонии. 105 лет назад эстонские войска напихали оркам в панамку и провозгласили новое независимое государство.</p> <center> <img src="/images/2023/02/independence-day-estonia.png" width="300" /> </center> <blockquote> <p>Если бы не те бравые ребята на бронепоезде, не было бы сейчас Селенида. :)</p> </blockquote> <p><br /></p> <h1 id="upd-вышла-selenide-6121">UPD Вышла Selenide 6.12.1</h1> <p>Исправили старинную багу в методе <code class="language-plaintext highlighter-rouge">using</code>.</p> <p>См. <a href="https://github.com/selenide/selenide/milestone/176?closed=1">changelog</a></p> <p><br /></p> <h1 id="upd-вышла-selenide-6122">UPD Вышла Selenide 6.12.2</h1> <p>По-быстрому залепили костыль для баги в Chromedriver 111:<br /> <code class="language-plaintext highlighter-rouge">Invalid Status code=403 text=Forbidden</code></p> <p>См. <a href="https://github.com/selenide/selenide/milestone/178?closed=1">changelog</a></p> <p><br /></p> <h1 id="upd-вышла-selenide-6123">UPD Вышла Selenide 6.12.3</h1> <p>Исправили одну старую багу в методе <code class="language-plaintext highlighter-rouge">$.download(FOLDER)</code>, если его вызвать после <code class="language-plaintext highlighter-rouge">using</code>.</p> <p>См. <a href="https://github.com/selenide/selenide/milestone/179?closed=1">changelog</a></p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2023/02/24/selenide-6.12.0/ http://ru.selenide.org/2023/02/24/selenide-6.12.0 2023-02-24T00:00:00+00:00 Вышла Selenide 6.11.1 <p>Хаюшки!</p> <p>Одна моя знакомая из Италии рассказала, что вышел новый релиз <a href="https://github.com/selenide/selenide/milestone/174?closed=1">Selenide 6.11.1</a>.</p> <ul class="blogpost-menu"> <li><a href="#truncate-webdriver-exception-message">Обрезаем только WebDriverException</a></li> <li><a href="#fix-download-to-folder">Чутка подправили $.download(FOLDER)</a></li> <li><a href="#update-dependencies">Обновили зависимости</a></li> <li><a href="#statistics">Статистика</a></li> </ul> <h3 id="truncate-webdriver-exception-message">Обрезаем только сообщения <code class="language-plaintext highlighter-rouge">WebDriverException</code></h3> <p>В довольно редких ситуациях - если вы</p> <ul> <li>используете кастомное действие (custom command),</li> <li>и из него кидаете какую-то свою ошибку (assertion error),</li> <li>и текст этой ошибки содержит несколько строк,</li> </ul> <p>то Селенид обрезает этот текст, оставляя лишь первую строку. Изначально планировалось обрезать только текст <code class="language-plaintext highlighter-rouge">WebDriverException</code>, потому что он объективно содержит многострочный мусор:</p> <blockquote> <p>The element could not be found (WARNING: The server did not provide any stacktrace information) Command duration or timeout: 21 milliseconds For documentation on this error … Build info: version: ‘2.29.1’, … System info: os.name: ‘Linux’, … Session ID: 610138404f5c18… Driver info: org.openqa.selenium.chrome.ChromeDriver</p> </blockquote> <p>Но как-то так вышло, что селенид обрезал текст не только <code class="language-plaintext highlighter-rouge">WebDriverException</code>, а вообще всех ошибок. Теперь подправили, и свой многострочный текст вы увидите целиком.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/2131">PR 2131</a>.</p> <p><br /></p> <h3 id="fix-download-to-folder">Чутка подправили <code class="language-plaintext highlighter-rouge">$.download(FOLDER)</code></h3> <p>Это очень редко случай, так что вы наверняка этого не замечали.</p> <p>Но наши тесты изредка моргали, и я покопал-покопал, да и раскопал парочку редких багов в методе <code class="language-plaintext highlighter-rouge">$.download(FOLDER)</code>. Иногда он мог кинуть ошибку, что файл не скачался (хоть он на самом деле скачался), в двух случаях:</p> <ul> <li> <p><a href="https://github.com/selenide/selenide/pull/2116">#2116</a> Если время изменения оказалось в предыдущей секунде от начала скачивания<br /> (такое бывает, т.к. разные файловые системы выдают время изменения файла с погрешностью до секунды, и иногда оно может даже оказаться в прошлом)</p> </li> <li> <p><a href="https://github.com/selenide/selenide/pull/2119">#2119</a> Если ОС вернула время последнего изменения файла “0”<br /> (оказываете, и такое бывает - если файловая система почему-то решила, что имя файла некорректное)</p> </li> </ul> <p>Теперь должно качаться как намасленное.</p> <p><br /></p> <h3 id="update-dependencies">Обновили зависимости</h3> <ul> <li>bump WebdriverManager from 5.3.1 to 5.3.2</li> <li>bump Netty from 4.1.86.Final to 4.1.87.Final, см. <a href="https://github.com/selenide/selenide/pull/2126">PR 2126</a>.</li> </ul> <p><br /></p> <h3 id="news">News</h3> <ul> <li>Пост от Amuthan Sakthivel <a href="https://creatingvalue.substack.com/p/why-we-chose-selenide-over-selenium">Почему мы выбрали Селенид, а не Селениум</a></li> <li>Свежая статья на хабре <a href="https://habr.com/ru/company/rostelecom/blog/707710/">Как написать UI-автотесты, если не умеешь программировать?</a></li> <li>Мой доклад в девклубе <a href="https://www.youtube.com/watch?v=VtX7IpCHMS8&amp;ab_channel=DEVCLUB.EU">Как законтрибьютить в опенсорс, чтобы не сгореть со стыда</a></li> <li>Мой доклад в девклубе <a href="https://www.youtube.com/watch?v=JKxzELiwO_o&amp;ab_channel=DEVCLUB.EU">WTF Thread Pools</a></li> </ul> <p><br /></p> <h3 id="statistics">Статистика</h3> <p>Количество ежемесячных скачиваний Селенида перевалило за 490 тыщ!</p> <center> <img src="/images/2023/01/selenide.downloads.png" width="800" /> </center> <p>Поднажмём…</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2023/01/20/selenide-6.11.1/ http://ru.selenide.org/2023/01/20/selenide-6.11.1 2023-01-20T00:00:00+00:00 Вышла Selenide 6.11.0 <center> <img src="/images/2023/01/selenide-6.11.0.png" width="700" /> </center> <p><br /></p> <h1 id="с-новым-годом-друзья">С Новым Годом, друзья!</h1> <p>Дедушка Мороз принёс нам новый релиз <a href="https://github.com/selenide/selenide/milestone/169?closed=1">Selenide 6.11.0</a>.</p> <ul class="blogpost-menu"> <li><a href="#added-copy-paste-methods">Методы для копирования текста</a></li> <li><a href="#fix-download-with-credentials">Скачивание файла за BasicAuth</a></li> <li><a href="#download-large-files-via-proxy">Скачиваем большие файлы через прокси</a></li> <li><a href="#can-handle-unexpected-alerts">Неожиданные алерты</a></li> <li><a href="#fix-screenshot-file-permission">Пермиссии файла скриншота</a></li> <li><a href="#support-as-annotation">Аннотация @As для полей без @FindBy</a></li> <li><a href="#last-page-source">Последний исходник страницы</a></li> <li><a href="#page-url-in-error-message">URL страницы в ошибке</a></li> </ul> <h3 id="added-copy-paste-methods">Добавили методы для копирования текста</h3> <p>Мы добавили два новых метода:</p> <ul> <li><code class="language-plaintext highlighter-rouge">Selenide.copy()</code> - копирует выделенный текст в буфер обмена, и</li> <li><code class="language-plaintext highlighter-rouge">$.paste()</code> вставляет текст из буфера обмена в поле ввода.</li> </ul> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">open</span><span class="o">(</span><span class="s">"https://best-propaganda-quotes.ru"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#solovjov"</span><span class="o">).</span><span class="na">doubleClick</span><span class="o">();</span> <span class="c1">// select the quote text</span> <span class="nc">Selenide</span><span class="o">.</span><span class="na">copy</span><span class="o">();</span> <span class="err">$</span><span class="o">(</span><span class="s">"[name=q]"</span><span class="o">).</span><span class="na">paste</span><span class="o">();</span> <span class="err">$</span><span class="o">(</span><span class="s">"[name=q]"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Обсираться мелкими алмазами на берегу озера Комо"</span><span class="o">));</span> </code></pre></div></div> <p>Известные ограничения: пока что эти методы не работают на серверных линуксах (без графического окружения). Но запуск xvfb должен помочь.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1817">issue 1817</a>.<br /> Спасибо <a href="https://github.com/evpl">Evgenii Plugatar</a> за <a href="https://github.com/selenide/selenide/pull/2027">PR 2027</a>.</p> <p><br /></p> <h3 id="fix-download-with-credentials">Исправили метод <code class="language-plaintext highlighter-rouge">Selenide.download(url)</code></h3> <p>…для случая, когда url содержит логин/пароль (т.е. ресурс защищён BasicAuth).</p> <p>Например, такой код раньше работал, но сломался после обновления Apache Http client:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">File</span> <span class="n">f</span> <span class="o">=</span> <span class="nc">Selenide</span><span class="o">.</span><span class="na">download</span><span class="o">(</span><span class="s">"https://admin:tiger@the-internet.herokuapp.com/basic_auth"</span><span class="o">);</span> </code></pre></div></div> <p>Оказалось, что в Apache Http client усилили валидацию URL, и часть с логином и паролем больше не разрешена (это типа небезопасная практика).</p> <p>Ну а селенид теперь вырезает эту часть и посылает с запросом в заголовке <code class="language-plaintext highlighter-rouge">Authorization</code>.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2037">issue 2037</a> и <a href="https://github.com/selenide/selenide/pull/2102">PR 2102</a>.</p> <p><br /></p> <h3 id="download-large-files-via-proxy">Позволяем скачивать большие файлы через прокси</h3> <p>Если вы скачиваете файлы методом <code class="language-plaintext highlighter-rouge">PROXY</code>, то размер файла не мог превышать 64 мегабайта. Изначально это казалось разумным ограничением: зачем кому-то нужно нагружать тестовый стенд, скачивая гигантские файлы? (64 и то многовато, по умолчанию в BrowserUpProxy вообще было 2 мегабайта; мы увеличили лимит до 64 в селениде)</p> <p>Но оказалось, что иногда люди хотят тестировать именно скачивание больших файлов. После долгих споров мы решили просто убрать это ограничение. Вам виднее, качайте сколько хотите.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">File</span> <span class="n">favoriteMovie</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#topMovie"</span><span class="o">).</span><span class="na">download</span><span class="o">();</span> <span class="n">assertThat</span><span class="o">(</span><span class="n">favoriteMovie</span><span class="o">)</span> <span class="o">.</span><span class="na">hasName</span><span class="o">(</span><span class="s">"BadSanta.avi"</span><span class="o">)</span> <span class="o">.</span><span class="na">as</span><span class="o">(</span><span class="s">"2 GB"</span><span class="o">).</span><span class="na">hasSize</span><span class="o">(</span><span class="mi">2147483648L</span><span class="o">);</span> </code></pre></div></div> <p>P.S. Но имейте в виду, со слишком большими файлами, скорее всего, прокси всё равно не справится (либо будет скачивать слишком долго). И BrowserUpProxy по-прежнему имеет встроенное техническое ограничение в 2 гигабайта (потому, что тип данных - Integer).</p> <p>Но хотя бы файлы по 200 мегабайтов вы вполне сможете скачивать.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2082">issue 2082</a> и <a href="https://github.com/selenide/selenide/pull/2098">PR 2098</a>.</p> <p><br /></p> <h3 id="can-handle-unexpected-alerts">Можно обрабатывать неожиданные алерты</h3> <p>По умолчанию, селенид игнорирует неожиданные алерты в браузере (точнее, запускает вебдрайвер с опцией <code class="language-plaintext highlighter-rouge">capabilities.setCapability(UNHANDLED_PROMPT_BEHAVIOUR, ACCEPT)</code>).</p> <p>С одной стороны, это удобно, чтобы тесты не ломались от внезапно всплывающих реклам и других бесполезных сообщений. С другой стороны, иногда эти алерты могут содержать полезную информацию - в частности, ценное сообщение об ошибке.</p> <p>Если это ваш случай, теперь вы можете переопределить эту настройку:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">org</span><span class="o">.</span><span class="na">openqa</span><span class="o">.</span><span class="na">selenium</span><span class="o">.</span><span class="na">remote</span><span class="o">.</span><span class="na">CapabilityType</span><span class="o">.</span><span class="na">UNHANDLED_PROMPT_BEHAVIOUR</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">static</span> <span class="n">org</span><span class="o">.</span><span class="na">openqa</span><span class="o">.</span><span class="na">selenium</span><span class="o">.</span><span class="na">UnexpectedAlertBehaviour</span><span class="o">.</span><span class="na">ACCEPT_AND_NOTIFY</span><span class="o">;</span> <span class="nc">Configuration</span><span class="o">.</span><span class="na">browserCapabilities</span><span class="o">.</span><span class="na">setCapability</span><span class="o">(</span><span class="no">UNHANDLED_PROMPT_BEHAVIOUR</span><span class="o">,</span> <span class="no">ACCEPT_AND_NOTIFY</span><span class="o">);</span> </code></pre></div></div> <p>И тогда при возникновении нежданных алертов вы узнаете, какой текст в них был:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">UnhandledAlertException:</span> <span class="n">unexpected</span> <span class="n">alert</span> <span class="nl">open:</span> <span class="o">{</span><span class="nc">Alert</span> <span class="n">text</span> <span class="o">:</span> <span class="nc">Как</span> <span class="n">жопа</span><span class="o">,</span> <span class="n">рогозин</span><span class="o">?}</span> <span class="c1">// chrome</span> <span class="nl">UnhandledAlertException:</span> <span class="nc">Accepted</span> <span class="n">user</span> <span class="n">prompt</span> <span class="nl">dialog:</span> <span class="nc">Маршрут</span> <span class="n">через</span> <span class="n">мост</span> <span class="n">недоступен</span><span class="o">.</span> <span class="nc">Чот</span> <span class="n">бахнуло</span><span class="o">.</span> <span class="c1">// firefox</span> <span class="nl">UnhandledAlertException:</span> <span class="n">unexpected</span> <span class="n">alert</span> <span class="nl">open:</span> <span class="o">{</span><span class="nc">Alert</span> <span class="n">text</span> <span class="o">:</span> <span class="nc">Обнаружены</span> <span class="n">боевые</span> <span class="n">комары</span><span class="o">-</span><span class="n">убийцы</span><span class="o">}</span> <span class="c1">// edge</span> <span class="nl">UnhandledAlertException:</span> <span class="o">:</span> <span class="nc">Обнаружена</span> <span class="n">грязная</span> <span class="n">бомба</span> <span class="c1">// safari</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2054">issue 2054</a> и <a href="https://github.com/selenide/selenide/pull/2095">PR 2095</a>.</p> <p><br /></p> <h3 id="fix-screenshot-file-permission">Исправили пермиссии файла скриншота</h3> <p>Как вы знаете, при падении теста селенид автоматически сохраняет скриншот и создаёт два файла: <code class="language-plaintext highlighter-rouge">*.png</code> и <code class="language-plaintext highlighter-rouge">*.html</code>. Так вот выяснилось, что селенид создаёт эти два файла с разными пермиссиями:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-rw------- 1 root root 300295 Dec 19 10:24 1671441847908.0.png -rw-r--r-- 1 root root 185070 Dec 19 10:24 1671441847908.0.html </code></pre></div></div> <p>И кое-кому это помешало писать сложносочинённые CI скрипты, выполняющие команды из-под разных юзеров. <em>Чем бы девопс не тешился… :)</em></p> <p>В общем, теперь у обоих будет “обычные” пермиссии <code class="language-plaintext highlighter-rouge">-rw-r--r--</code>.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2081">issue 2081</a> и <a href="https://github.com/selenide/selenide/pull/2084">PR 2084</a>.</p> <p><br /></p> <h3 id="support-as-annotation">Поддержка аннотации <code class="language-plaintext highlighter-rouge">@As</code> для полей без <code class="language-plaintext highlighter-rouge">@FindBy</code></h3> <p>В селениде уже давно можно задавать удобные имена элементам пэдж обжекты (т.н. “алиасы”) с помощью метода <code class="language-plaintext highlighter-rouge">as</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">LoginPage</span> <span class="o">{</span> <span class="nc">SelenideElement</span> <span class="n">loginButton</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="nc">By</span><span class="o">.</span><span class="na">xpath</span><span class="o">(</span><span class="s">"/long/ugly/xpath[3]"</span><span class="o">)).</span><span class="na">as</span><span class="o">(</span><span class="s">"Login button"</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>Но кому-то показалось, что удобно было бы повесить имя элемента в начало строки, а то справа от длинного селектора оно визуально теряется.</p> <p>В общем, теперь алиас можно задать и с помощью аннотации <code class="language-plaintext highlighter-rouge">@As</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">LoginPage</span> <span class="o">{</span> <span class="nd">@As</span><span class="o">(</span><span class="s">"Login button"</span><span class="o">)</span> <span class="nc">SelenideElement</span> <span class="n">loginButton</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="nc">By</span><span class="o">.</span><span class="na">xpath</span><span class="o">(</span><span class="s">"/long/ugly/xpath[3]"</span><span class="o">));</span> <span class="o">}</span> </code></pre></div></div> <p>Но естественно, аннотация сработает, только если вы инициализируете пэдж обжект с помощью метода <code class="language-plaintext highlighter-rouge">Selenide.page()</code> или <code class="language-plaintext highlighter-rouge">Selenide.open()</code></p> <p>См. <a href="https://github.com/selenide/selenide/issues/2087">issue 2087</a> и <a href="https://github.com/selenide/selenide/pull/2088">PR 2088</a>.</p> <p><br /></p> <h3 id="last-page-source">Метод для последнего сохранённого исходника страницы</h3> <p>Редко когда это нужно, так что не заморачивайтесь. По сути добавили методы <code class="language-plaintext highlighter-rouge">ScreenShotLaboratory</code>: <code class="language-plaintext highlighter-rouge">threadScreenshots()</code>, <code class="language-plaintext highlighter-rouge">contextScreenshots()</code>, <code class="language-plaintext highlighter-rouge">lastThreadScreenshot()</code>, <code class="language-plaintext highlighter-rouge">lastContextScreenshot()</code>.</p> <p>Спасибо <a href="https://github.com/armanayvazyan">Arman Ayvazyan</a> за <a href="https://github.com/selenide/selenide/pull/2065">PR 2065</a>.</p> <p><br /></p> <h3 id="page-url-in-error-message">Теперь можно добавлять URL страницы в сообщение об ошибке</h3> <p>Кому-то это полезно, кому-то вредно. После долгих споров сделали эту возможность опциональной (в виде плагина).</p> <p>Пусть пока побудет в статусе экспериментальной возможности. Вероятно, с форматами сообщений об ошибках мы ещё будем играться.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/980">issue 980</a> и <a href="https://github.com/selenide/selenide/pull/2097">PR 2097</a>.</p> <p><br /></p> <h3 id="year-summary">Итоги года</h3> <p>Подведём итоги 2022 года? За этот год Selenide был упомянут в нескольких топах:</p> <ul> <li><a href="https://qameta.io/blog/5-testing-automation-tools/">5 Testing Automation Tools</a> в блоге компании Qameta Software</li> <li><a href="https://hackernoon.com/top-java-libraries-for-automation-testing-in-2022">Top Java Libraries for Automation Testing in 2022</a></li> <li><a href="https://aglowiditsolutions.com/blog/top-java-frameworks/">Top Java Frameworks to Use in 2022</a></li> </ul> <p>И наконец,</p> <ul> <li>Selenide упомянут на <a href="https://www.selenium.dev/ecosystem/">официальном сайте Selenium</a> в разделе “Экосистема”.</li> </ul> <p>Количество скачиваний селенида выросло аж <strong>в полтора раза</strong>:</p> <blockquote> <p>с 302 тысяч в январе до 469 тысяч в ноябре.</p> </blockquote> <h3 id="new-year-wishes">И всё-таки</h3> <p>Это был ужасный год. Но я рад, что я смог использовать накопленный багаж в виде сайта selenide.org и его аудитории, чтобы распространять антивоенную позицию. Кажется, здесь собрались люди, которые эту позицию разделяют. Чему я тоже очень рад.</p> <p>Надеюсь, в наступившем году война закончится, виновные будут наказаны, граждане угнетённых стран сбросят наконец своих тиранов. А сомневающиеся вытащат наконец голову из жопы.</p> <p>А прекрасная свободная страна Украина отстроится и будет цвести пуще прежнего.</p> <blockquote> <p>И через год мы с вами увидимся в Киеве на замечательной <a href="https://seleniumcamp.com/">конференции SeleniumCamp</a>.</p> </blockquote> <p>Героям слава!</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2023/01/03/selenide-6.11.0/ http://ru.selenide.org/2023/01/03/selenide-6.11.0 2023-01-03T00:00:00+00:00 Вышла Selenide 6.10.2 <p><br /></p> <h1 id="всем-привет">Всем привет!</h1> <p>У нас вышел новый мини-релиз <a href="https://github.com/selenide/selenide/milestone/171?closed=1">Selenide 6.10.2</a>.</p> <ul class="blogpost-menu"> <li><a href="#added-method-press">Добавили метод $.press()</a></li> <li><a href="#trigger-change-events-by-select-methods">Генерируем события change в методах $.select*</a></li> <li><a href="#friendly-select-option-in-reports">selectOption в отчётах</a></li> <li><a href="#friendly-local-storage-in-reports">localStorage в отчётах</a></li> <li><a href="#news">Новости</a></li> </ul> <h3 id="added-method-press">Добавили метод <code class="language-plaintext highlighter-rouge">$.press()</code></h3> <p>По сути это то же самое, что <code class="language-plaintext highlighter-rouge">sendKeys()</code>, только он не <code class="language-plaintext highlighter-rouge">void</code>. То есть его можно <em>чейнить</em> с другими методами:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#username"</span><span class="o">)</span> <span class="o">.</span><span class="na">press</span><span class="o">(</span><span class="s">"x"</span><span class="o">)</span> <span class="o">.</span><span class="na">press</span><span class="o">(</span><span class="no">TAB</span><span class="o">,</span> <span class="no">CONTROL</span><span class="o">,</span> <span class="no">ALT</span><span class="o">,</span> <span class="no">ENTER</span><span class="o">)</span> <span class="o">.</span><span class="na">should</span><span class="o">(</span><span class="n">disappear</span><span class="o">);</span> </code></pre></div></div> <p>Спасибо <a href="https://github.com/amuthansakthivel">Amuthan Sakthivel</a> за <a href="https://github.com/selenide/selenide/pull/2032">PR 2032</a>.</p> <p><br /></p> <h3 id="trigger-change-events-by-select-methods">Генерируем события <code class="language-plaintext highlighter-rouge">change</code> в методах <code class="language-plaintext highlighter-rouge">$.select*</code></h3> <p>Как вы помните, в предыдущем релизе мы <a href="/2022/11/21/selenide-6.10.0/#select-options-using-javascript">переделали работу с селектами на JavaScript</a>. Но при этом забыли, что надо ещё и генерировать события <code class="language-plaintext highlighter-rouge">focus</code>, <code class="language-plaintext highlighter-rouge">click</code>, <code class="language-plaintext highlighter-rouge">change</code>. Теперь генерируем.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/2050">issue 2050</a>. Спасибо <a href="https://github.com/cocorossello">Vicente Rossello Jaume</a> за <a href="https://github.com/selenide/selenide/pull/2051">PR 2051</a>.</p> <p>UPD. Исправили ещё раз в <a href="https://github.com/selenide/selenide/milestone/172?closed=1">Selenide 6.10.3</a>.</p> <p><br /></p> <h3 id="friendly-select-option-in-reports">Показываем <code class="language-plaintext highlighter-rouge">$.selectOption()</code> в отчётах по-человечески</h3> <p>Ещё один косячок, вылезший после предыдущего рефакторинга селектов: в отчётах выскочили нечитаемые параметры. Это всё потому, что в Java у массивов нет стандартного метода <code class="language-plaintext highlighter-rouge">toString()</code>, приходится изобретать велосипед.</p> <p>Было:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>| #blockChannel | select option([Канал Дождь, [Ljava.lang.String;@6732726]) | PASS | 487 | </code></pre></div></div> <p>Стало:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>| #blockChannel | select option(Канал Дождь) | PASS | 487 | </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2047">issue 2047</a> и <a href="https://github.com/selenide/selenide/pull/2052">PR 2052</a>.</p> <p><br /></p> <h3 id="friendly-local-storage-in-reports">Показываем <code class="language-plaintext highlighter-rouge">localStorage</code> в отчётах по-человечески</h3> <p>Почти такая же проблема: операции с <code class="language-plaintext highlighter-rouge">sessionStorage</code> и <code class="language-plaintext highlighter-rouge">localStorage</code> выглядели в отчётах нечитабельно.</p> <p>Было:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>| com.codeborne.selenide.LocalStorage@138a952f | set item(['Бут', 9125]) | | com.codeborne.selenide.SessionStorage@549w123gg | set item(['Грайнер', 3285]) | </code></pre></div></div> <p>Стало:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>| localStorage | set item(['Бут', 9125]) | | sessionStorage | set item(['Грайнер', 3285]) | </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2045">issue 2045</a> и <a href="https://github.com/selenide/selenide/pull/2046">PR 2046</a>.</p> <p><br /></p> <h3 id="update-dependencies">Обновили зависимости</h3> <ul> <li>#2044 #2057 bump Selenium from 4.6.0 to 4.7.1</li> <li>#2036 bump browserup-proxy-core from 2.2.5 to 2.2.6</li> <li>#2058 bump httpclient5 from 5.2 to 5.2.1</li> <li>bump slf4j from 2.0.4 to 2.0.5</li> </ul> <p><br /></p> <h3 id="дочерние-проекты">Дочерние проекты</h3> <p>Также зарелизили наши дочерние проекты:</p> <ul> <li><a href="https://github.com/selenide/selenide-appium/releases/tag/v2.4.0">selenide-appium 2.4.0</a></li> <li><a href="https://github.com/selenide/selenide-selenoid/releases/tag/v2.3.3">selenide-selenoid 2.3.3</a></li> </ul> <p><br /></p> <h3 id="news">Новости</h3> <ul> <li>Selenide Tutorial: <a href="https://www.youtube.com/watch?v=5vrYMfsxkGY&amp;list=PL9ok7C7Yn9A9YyRISFrxHdaxb5qqrxp_i&amp;index=4&amp;ab_channel=TestingMiniBytes">Replacement for Selenium?</a> на канале Testing Mini Bytes</li> <li><a href="https://oleksandr-podoliako.medium.com/test-automation-framework-for-ui-testing-with-java-fddd1e3fd75b">Test automation framework for UI testing with java</a> от Oleksandr Podoliako</li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2022/12/08/selenide-6.10.2/ http://ru.selenide.org/2022/12/08/selenide-6.10.2 2022-12-08T00:00:00+00:00 Вышла Selenide 6.10.0 <p><br /></p> <h1 id="недобрый-вечер">Недобрый вечер!</h1> <p>Вышел новый релиз <a href="https://github.com/selenide/selenide/milestone/167?closed=1">Selenide 6.10.0</a>.</p> <ul class="blogpost-menu"> <li><a href="#slow-download-in-firefox">Улучшили алгоритм скачивания файлов</a></li> <li><a href="#fail-download-early">Ускорили отрицательное скачивание файла</a></li> <li><a href="#select-options-using-javascript">Выбираем опции через JavaScript</a></li> <li><a href="#make-click-chainable">Сделали клик “чейнебл”</a></li> <li><a href="#fix-size-for-new-tabs">Размер окна для новых вкладок</a></li> <li><a href="#encode-basic-auth-credentials-in-url">BasicAuth со спецсимволами</a></li> <li><a href="#news">Новости</a></li> </ul> <h3 id="slow-download-in-firefox">Улучшили алгоритм скачивания файлов</h3> <p>Один из алгоритмов скачивания в Selenide - это FOLDER. Чтобы скачать файл, он кликает нужную кнопку и ждёт, пока в папке “Downloads” появится нужный файл.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">File</span> <span class="n">еноты</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#stolenRaccoonsReport"</span><span class="o">).</span><span class="na">download</span><span class="o">(</span><span class="n">using</span><span class="o">(</span><span class="no">FOLDER</span><span class="o">));</span> <span class="n">assertThat</span><span class="o">(</span><span class="n">еноты</span><span class="o">).</span><span class="na">hasName</span><span class="o">(</span><span class="s">"еноты.xls"</span><span class="o">);</span> </code></pre></div></div> <p>Проблема в том, что этот алгоритм не очень хорошо работал в Firefox, когда скачивание идёт очень медленно. Оказалось, что Firefox сразу создаёт в папке два файла: “еноты.xls” и “еноты.xls.part”, и оба пустые. И лишь затем начинает их потихоньку заполнять.</p> <p><br /> В общем, наш алгоритм стал умнее. Теперь он</p> <ol> <li>Ждёт, когда в папке появятся хоть какие-нибудь подходящие файлы.</li> <li>Ждёт, когда пропадут все файлы <code class="language-plaintext highlighter-rouge">*part</code> (в Firefox).</li> <li>Ждёт, когда пропадут все файлы <code class="language-plaintext highlighter-rouge">*crdownload</code> (в Chrome).</li> <li>Ждёт, когда все файлы замрут как минимум на секунду (в остальных браузерах).</li> </ol> <p>Такой подход должен обеспечить более надёжное скачивание файлов.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1989">issue 1989</a> и <a href="https://github.com/selenide/selenide/pull/2003">PR 2003</a>.</p> <p><br /></p> <h3 id="fail-download-early">Ускорили отрицательное скачивание файла</h3> <p>Часто люди выставляют большой таймаут на скачивание файла. Особенно если файл большой:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">File</span> <span class="n">video</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#skaebova"</span><span class="o">).</span><span class="na">download</span><span class="o">(</span><span class="n">using</span><span class="o">(</span><span class="no">FOLDER</span><span class="o">)</span> <span class="o">.</span><span class="na">withTimeout</span><span class="o">(</span><span class="nc">Duration</span><span class="o">.</span><span class="na">ofSeconds</span><span class="o">(</span><span class="mi">99</span><span class="o">))</span> <span class="o">.</span><span class="na">withName</span><span class="o">(</span><span class="s">"пыня мобшиза.MP4"</span><span class="o">));</span> </code></pre></div></div> <p>Но незачем ждать так долго, если скачивание даже не началось. Например, если клик тупо не попал по кнопке (как это бывает, я рассказывал в <a href="https://www.youtube.com/watch?v=elQ2LGGU2bg&amp;ab_channel=DEVCLUB.EU&amp;t=21m32s">видео “Flaky tests”</a>.</p> <p>Для ускорения падения теперь можно задать второй параметр “increment timeout”:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">File</span> <span class="n">video</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#skaebova"</span><span class="o">).</span><span class="na">download</span><span class="o">(</span><span class="n">using</span><span class="o">(</span><span class="no">FOLDER</span><span class="o">)</span> <span class="o">.</span><span class="na">withTimeout</span><span class="o">(</span><span class="n">ofSeconds</span><span class="o">(</span><span class="mi">99</span><span class="o">))</span> <span class="o">.</span><span class="na">withIncrementTimeout</span><span class="o">(</span><span class="n">ofSeconds</span><span class="o">(</span><span class="mi">2</span><span class="o">))</span> <span class="o">.</span><span class="na">withName</span><span class="o">(</span><span class="s">"пыня мобшиза.MP4"</span><span class="o">));</span> </code></pre></div></div> <p>В этом случае общий таймаут на скачивание 99 секунд, НО если в течение 2 секунд не было никаких изменений в папке для скачивания, то метод выкинет ошибку сразу.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1990">issue 1990</a> и <a href="https://github.com/selenide/selenide/pull/2023">PR 2023</a>.</p> <p><br /></p> <h3 id="select-options-using-javascript">Выбираем опции в <code class="language-plaintext highlighter-rouge">&lt;select&gt;</code> через JavaScript</h3> <p>Это должно сделать работу с селектами быстрее. И теперь селенид выкидывает более подробную ошибку, если <code class="language-plaintext highlighter-rouge">&lt;select&gt;</code> (или <code class="language-plaintext highlighter-rouge">&lt;option&gt;</code>) оказался <code class="language-plaintext highlighter-rouge">disabled</code>.</p> <p>Например, для такого селекта:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;select</span> <span class="na">id=</span><span class="s">"region"</span><span class="nt">&gt;</span> <span class="nt">&lt;option</span> <span class="na">value=</span><span class="s">"belgorod"</span><span class="nt">&gt;</span>Belgorod<span class="nt">&lt;/option&gt;</span> <span class="nt">&lt;option</span> <span class="na">value=</span><span class="s">"kherson"</span> <span class="na">disabled</span><span class="nt">&gt;</span>Kherson<span class="nt">&lt;/option&gt;</span> <span class="nt">&lt;option</span> <span class="na">value=</span><span class="s">"zaporozhia"</span> <span class="na">disabled</span><span class="nt">&gt;</span>Zaporozhia<span class="nt">&lt;/option&gt;</span> <span class="nt">&lt;/select&gt;</span> </code></pre></div></div> <p>Попытка выбрать <code class="language-plaintext highlighter-rouge">disabled</code> опцию:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#region"</span><span class="o">).</span><span class="na">selectOption</span><span class="o">(</span><span class="s">"Kherson"</span><span class="o">);</span> </code></pre></div></div> <p>выдаст понятную ошибку с подробным объяснением:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Invalid</span> <span class="n">element</span> <span class="n">state</span> <span class="o">[</span><span class="err">#</span><span class="n">region</span><span class="o">/</span><span class="n">option</span><span class="o">[</span><span class="nl">text:</span><span class="nc">Kherson</span><span class="o">]]:</span> <span class="nc">Cannot</span> <span class="n">select</span> <span class="n">a</span> <span class="n">disabled</span> <span class="n">option</span> </code></pre></div></div> <p>Раньше эта ошибка была не такой подробной:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">UnsupportedOperationException</span><span class="o">:</span> <span class="nc">You</span> <span class="n">may</span> <span class="n">not</span> <span class="n">select</span> <span class="n">a</span> <span class="n">disabled</span> <span class="n">option</span> </code></pre></div></div> <p>(а ещё раньше такой тест вообще не падал, но и опцию не выбирал)</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1553">issue 1553</a> и <a href="https://github.com/selenide/selenide/pull/1876">PR 1876</a>.</p> <blockquote> <p>Отдельное спасибо <a href="https://github.com/bereg2k">Oleg Berezhnoy</a> за <a href="https://github.com/selenide/selenide/pull/1553">PR 1553</a>, который хоть и не попал в селенид, но инициировал целую дискуссию и в селениде, и в самом селениуме, в т.ч. о том, за что должен или не должен отвечать селениум, и что такое “просто фреймворк” и “опионейтед фреймворк”.</p> </blockquote> <p><br /></p> <h3 id="make-click-chainable">Сделали <code class="language-plaintext highlighter-rouge">$.click(options)</code> “чейнебл”</h3> <p>Люди часто жалуются, что метод <code class="language-plaintext highlighter-rouge">$.click()</code> имеет тип <code class="language-plaintext highlighter-rouge">void</code>, то есть его нельзя чейнить:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">".btn"</span><span class="o">).</span><span class="na">click</span><span class="o">().</span><span class="na">should</span><span class="o">(</span><span class="n">disappear</span><span class="o">);</span> </code></pre></div></div> <p>Увы, это мы исправить не можем, т.к. класс <code class="language-plaintext highlighter-rouge">SelenideElement</code> наследует метод <code class="language-plaintext highlighter-rouge">void click()</code> из селениумовского <code class="language-plaintext highlighter-rouge">WebElement</code>.</p> <p>Но мы сделали “чейнебл” другой <code class="language-plaintext highlighter-rouge">click</code> метод, который с параметрами (т.н. “оверлоадед”). Теперь хотя бы его можно “чейнить”:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">".btn"</span><span class="o">)</span> <span class="o">.</span><span class="na">click</span><span class="o">(</span><span class="n">usingDefaultMethod</span><span class="o">())</span> <span class="o">.</span><span class="na">should</span><span class="o">(</span><span class="n">disappear</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">".btn"</span><span class="o">)</span> <span class="o">.</span><span class="na">click</span><span class="o">(</span><span class="n">usingDefaultMethod</span><span class="o">().</span><span class="na">withOffset</span><span class="o">(</span><span class="mi">42</span><span class="o">,</span> <span class="mi">42</span><span class="o">))</span> <span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">cssClass</span><span class="o">(</span><span class="s">"alert"</span><span class="o">));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2007">issue 2007</a> и <a href="https://github.com/selenide/selenide/pull/2008">PR 2008</a>.</p> <p><br /></p> <h3 id="fix-size-for-new-tabs">Исправили размер окна для новых вкладок</h3> <p>Спасибо <a href="https://github.com/BorisOsipov">Boris Osipov</a> за <a href="https://github.com/selenide/selenide/pull/2017">PR 2017</a>.</p> <p>P.S. Исправили ещё раз в <a href="https://github.com/selenide/selenide/milestone/170?closed=1">Selenide 6.10.1</a></p> <p><br /></p> <h3 id="encode-basic-auth-credentials-in-url">Поддерживаем логин/пароль BasicAuth со спецсимволами</h3> <p>Selenide умеет открывать сайты, защищённые паролем (т.н. BasicAuth):</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">open</span><span class="o">(</span><span class="s">"/basic-auth/hello"</span><span class="o">,</span> <span class="no">BASIC</span><span class="o">,</span> <span class="k">new</span> <span class="nf">BasicAuthCredentials</span><span class="o">(</span><span class="s">""</span><span class="o">,</span> <span class="s">"Královec"</span><span class="o">,</span> <span class="s">"is Czechia /:)"</span><span class="o">));</span> </code></pre></div></div> <p>Эти логин-пароль добавляются либо в http заголовок <code class="language-plaintext highlighter-rouge">Authorization</code> (если прокси включён), либо в URL (если прокси выключен).</p> <p>Недавно я обнаружил, что второй способ работает некорректно, если логин или пароль содержат спецсимволы. При добавлении в URL эти символы не экранировались, и получался невалидный URL:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://Královec:is Czechia /:)@127.0.0.1:4405/basic-auth/hello </code></pre></div></div> <p>и браузер не мог открыть страницу.</p> <blockquote> <p>Мне по-настоящему неловко, что я как-то не увидел этой страницы. Надеюсь, вы меня простите.</p> </blockquote> <p>В общем, теперь такие хитрые пароли тоже должны работать. Селенид экранирует все спецсимволы и генерирует корректный URL:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://Kr%C3%A1lovec:is+Czechia+%2F%3A%29@127.0.0.1:27663/basic-auth/hello </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/2020">issue 2020</a> и <a href="https://github.com/selenide/selenide/pull/2021">PR 2021</a>.</p> <p><br /></p> <h3 id="update-dependencies">Обновили зависимости</h3> <ul> <li>Selenium from 4.5.0 to 4.6.0, см. <a href="https://www.selenium.dev/blog/2022/selenium-4-6-0-released/">ченджлог</a></li> <li>WebDriverManager from 5.3.0 to 5.3.1, см. <a href="https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md#531---2022-11-04">ченджлог</a></li> <li>BrowserUpProxy from 2.2.3 to 2.2.5, см. <a href="https://github.com/valfirst/browserup-proxy/blob/master/CHANGELOG.md">ченджлог</a></li> <li>Netty from 4.1.82.Final to 4.1.85.Final</li> <li>LittleProxy from 2.0.13 to 2.0.14, см. <a href="https://github.com/LittleProxy/LittleProxy/milestone/19?closed=1">ченджлог</a></li> <li>#2014 Bump httpclient5 from 5.1.3 to 5.2, см. <a href="https://github.com/selenide/selenide/pull/2014">PR 2014</a></li> <li>#2025 bump slf4j from 2.0.3 to 2.0.4, см. <a href="https://github.com/selenide/selenide/pull/2025">PR 2025</a></li> </ul> <p><br /></p> <h3 id="дочерние-проекты">Дочерние проекты</h3> <p>Также зарелизили наши дочерние проекты:</p> <ul> <li><a href="https://github.com/selenide/selenide-appium/releases/tag/v2.3.0">selenide-appium 2.3.0</a></li> <li><a href="https://github.com/selenide/selenide-selenoid/releases/tag/v2.3.2">selenide-selenoid 2.3.2</a></li> </ul> <p><br /></p> <h3 id="news">Новости</h3> <ul> <li>JetBrains выпустила AQUA - новую <a href="https://www.jetbrains.com/aqua/">IDE для автотестов</a>! Клёвое лого!</li> <li>В Selenium появился свой встроенный <a href="https://www.selenium.dev/blog/2022/introducing-selenium-manager/">аналог WebDriverManager</a>. Кто-то уже попробовал?</li> <li>Новый фреймворк <a href="https://gitlab.com/brewcode/selenide-pages">Selenide Pages</a> на базе Selenide от Maxim Kochetkov. Клёвое лого!</li> </ul> <h3 id="my-videos">Мои свежие видосы</h3> <p>Появилось видео моих осенних докладов из таллиннского девклуба:</p> <ul> <li><a href="https://www.youtube.com/watch?v=VtX7IpCHMS8&amp;ab_channel=DEVCLUB.EU">Как законтрибьютить в опенсорс, чтобы не сгореть со стыда</a></li> <li><a href="https://www.youtube.com/watch?v=JKxzELiwO_o&amp;ab_channel=DEVCLUB.EU">WTF Thread Pools</a> - как накосячить с потоками в Java (с зубодробительными примерами из Selenium)</li> </ul> <h3 id="videos">Видосы и читосы</h3> <ul> <li>Видос <a href="https://www.youtube.com/watch?v=_X0rL1eUMK0&amp;ab_channel=OlehPendrak">Чтение логов из браузера через Selenide</a> от Oleh Pendrak</li> <li>Пост <a href="https://www.linkedin.com/pulse/all-selenide-muhammad-naeem/">All About Selenide</a> от Muhammad Naeem</li> <li>Видос <a href="https://morioh.com/p/018678871de9">Working with web elements using Selenide</a> от Automation Bro</li> <li>Пост <a href="https://dev.to/automationbro/page-object-model-selenide-tutorial-series-g3g">Page Object Model</a> из серии “Selenide Tutorial Series” от Automation Bro</li> <li>Пост <a href="https://habr.com/ru/company/innotech/blog/696140/">Как кастомизировать UI артефакты для Selenide + Selenoid + Allure (with TestOPS)</a> на Хабре</li> </ul> <p><br /></p> <h3 id="statistics">Статистика</h3> <ul> <li>Наша <a href="https://www.linkedin.com/groups/9154550/">группа в LinkedIn</a> насчитывает уже 176 участников. Присоединяйтесь!</li> <li>Подъехала свежая статистика скачиваний Селенида. Перевалили за 470 тыщ!</li> </ul> <center> <img src="/images/2022/11/selenide.downloads.png" width="800" /> </center> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2022/11/21/selenide-6.10.0/ http://ru.selenide.org/2022/11/21/selenide-6.10.0 2022-11-21T00:00:00+00:00 Вышла Selenide 6.9.0 <p><br /></p> <h1 id="привет">Привет!</h1> <p>Позвольте прервать ваш думскроллинг хорошей новостью.</p> <p>Вы выпустили <a href="https://github.com/selenide/selenide/milestone/166?closed=1">Selenide 6.9.0</a>! В основном прокачали прокси и обновили селениум.</p> <ul class="blogpost-menu"> <li><a href="#proxy-mock-response">Подменяем ответ сервера в прокси</a></li> <li><a href="#secure-authorization-header">Заголовок авторизации</a></li> <li><a href="#resolve-proxy-hostname">Подкрутили имя прокси хоста</a></li> <li><a href="#upgrade-to-selenium-4.5.0">Обновились на Selenium 4.5.0</a></li> <li><a href="#remove-opera-support">Выкинули поддержку Opera</a></li> <li><a href="#news">Новости</a></li> </ul> <h3 id="proxy-mock-response">Научили прокси подменять ответ сервера</h3> <p>Как вы знаете, селенид умеет запускать свой встроенный прокси между браузером и тестируемым приложением. До сих пор мы использовали его в основном для отслеживания запросов (логирования, скачивания файлов), но теперь ещё и добавили возможность подменить ответ сервера. Это удобно, например, чтобы замокать ответ какого-то сервиса.</p> <p>Давайте рассмотрим на каком-нибудь простеньком абстрактном примере.</p> <h4 id="пример">Пример</h4> <p>Допустим, вы тестируете сайт, показывающий результаты референдума. Это html-страница по адресу, скажем, https://referendum.ru, которая обращается к сервису https://cik.ru и тянет с него json с результатами голосования.</p> <p>Поскольку результаты заранее неизвестны, а сайт протестировать нужно здесь и сейчас, мы хотим проверить, как он будет выглядеть в разных пограничных случаях (corner cases).</p> <h4 id="тест">Тест</h4> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">open</span><span class="o">();</span> <span class="n">getSelenideProxy</span><span class="o">().</span><span class="na">responseMocker</span><span class="o">().</span><span class="na">mockText</span><span class="o">(</span><span class="s">"cik-mock"</span><span class="o">,</span> <span class="n">urlStartsWith</span><span class="o">(</span><span class="no">GET</span><span class="o">,</span> <span class="s">"https://cik.ru/api/gov/no/referendum"</span><span class="o">),</span> <span class="o">()</span> <span class="o">-&gt;</span> <span class="s">"{votes: 2133326, for: 99.23, against: 0.77}"</span><span class="o">);</span> <span class="n">open</span><span class="o">(</span><span class="s">"https://referendum.ru"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#votesFor"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"99.23%"</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">"#h3"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Не только порадовали, но и удивили"</span><span class="o">));</span> </code></pre></div></div> <h4 id="детали">Детали</h4> <p>Остановимся подробнее на первом параметре <code class="language-plaintext highlighter-rouge">cik-mock</code>. Это <em>имя</em> мока. Нужно оно для того, чтобы после теста его отменить (чтобы случайно не повлиять на следующие тесты):</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@AfterEach</span> <span class="kt">void</span> <span class="nf">tearDown</span><span class="o">()</span> <span class="o">{</span> <span class="n">getSelenideProxy</span><span class="o">().</span><span class="na">responseMocker</span><span class="o">().</span><span class="na">reset</span><span class="o">(</span><span class="s">"cik-mock"</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>Ну или для надёжности можно отменить <em>все</em> моки:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@AfterEach</span> <span class="kt">void</span> <span class="nf">tearDown</span><span class="o">()</span> <span class="o">{</span> <span class="n">getSelenideProxy</span><span class="o">().</span><span class="na">responseMocker</span><span class="o">().</span><span class="na">resetAll</span><span class="o">();</span> <span class="o">}</span> </code></pre></div></div> <h4 id="ограничения">Ограничения</h4> <p>Если страница и сервис работают на одном домене, ограничений нет. А вот если страница обращается к сервису на другом домене, то мок сработает только при выполнении условий:</p> <ul> <li>страница и сервис бегают на https (не http)</li> <li>сервис работает и физически доступен из прокси</li> </ul> <h4 id="в-общем">В общем</h4> <p>Использование моков - мощная техника, позволяющая вам проверять разные пограничные условия, которые иначе повторить сложно или невозможно (“146% голосов за”, “никто не явился на выборы”, “сервис недоступен” и т.д.)</p> <blockquote> <p>Не стесняйтесь своего желания что-то подправлять, подчищать, добавлять. Будет так, как вы захотите.</p> </blockquote> <p>См. <a href="https://github.com/selenide/selenide/issues/1254">issue 1254</a> и <a href="https://github.com/selenide/selenide/pull/1978">PR 1978</a>.</p> <p><br /></p> <h3 id="secure-authorization-header">Посылаем заголовок авторизации только нужному домену</h3> <p>Некоторые сайты, которые вам приходится тестировать, закрыты от внешнего мира с помощью BasicAuth. Селенид позволяет их открыть с помощью метода open с доп. параметрами:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">open</span><span class="o">(</span><span class="s">"https://referendum.ru/admin"</span><span class="o">,</span> <span class="no">BASIC</span><span class="o">,</span> <span class="k">new</span> <span class="nf">BasicAuthCredentials</span><span class="o">(</span><span class="s">"vlastelin"</span><span class="o">,</span> <span class="s">"gojda!!!"</span><span class="o">));</span> </code></pre></div></div> <p>Этот метод умеет обходить BasicAuth:</p> <ul> <li>если прокси выключен - добавлением логина-пароля в URL,</li> <li>а если прокси включен - добавлением заголовка <code class="language-plaintext highlighter-rouge">Authorization</code> в запросы от браузера к серверу.</li> </ul> <p>Но вот незадача. Недавно мы обнаружили, что селенид слал заголовок <code class="language-plaintext highlighter-rouge">Authorization</code> не только тестируемому приложению, но и всем сторонним сервисам, к которым оно могло обращаться (например, S3 или Google authentication).</p> <p>Теперь селенид будет посылать заголовок <code class="language-plaintext highlighter-rouge">Authorization</code> только на нужный домен, но и вам придётся указать этот домен в конструкторе:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">open</span><span class="o">(</span><span class="s">"https://referendum.ru/admin"</span><span class="o">,</span> <span class="no">BASIC</span><span class="o">,</span> <span class="k">new</span> <span class="nf">BasicAuthCredentials</span><span class="o">(</span><span class="s">"referendum.ru"</span><span class="o">,</span> <span class="s">"vlastelin"</span><span class="o">,</span> <span class="s">"gojda!!!"</span><span class="o">));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1974">issue 1974</a> и <a href="https://github.com/selenide/selenide/pull/1975">PR 1975</a>.</p> <p><br /></p> <h3 id="resolve-proxy-hostname">Подкрутили имя прокси хоста</h3> <p>Когда вы включаете прокси в селениде (например, через <code class="language-plaintext highlighter-rouge">Configuration.proxyEnabled = true</code>), селенид запускает встроенный прокси-сервер на случайном порту. И открывает браузер с указанием использовать прокси-сервер <code class="language-plaintext highlighter-rouge">HOST:PORT</code>. Вопрос, какой HOST тут использовать?</p> <p>До сих пор по умолчанию использовался результат команды <code class="language-plaintext highlighter-rouge">ClientUtil.getConnectableAddress()</code> (это поведение по умолчанию в BrowserUpProxy). Но с этого релиза будет использоваться <code class="language-plaintext highlighter-rouge">new NetworkUtils().getNonLoopbackAddressOfThisMachine()</code> (это метод из Selenium). Мне лень разбираться, в чём там их специфика, но на моём компе они иногда выдают разный результат:</p> <ul> <li><code class="language-plaintext highlighter-rouge">new NetworkUtils().getNonLoopbackAddressOfThisMachine()</code> -&gt; <code class="language-plaintext highlighter-rouge">192.168.0.18</code></li> <li><code class="language-plaintext highlighter-rouge">ClientUtil.getConnectableAddress()</code> -&gt; <code class="language-plaintext highlighter-rouge">127.0.0.1</code></li> </ul> <p>И первый однозначно лучше, когда браузер бежит на другой машине или в контейнере. Под адресом <code class="language-plaintext highlighter-rouge">127.0.0.1</code> прокси просто не будет виден с другой машины.</p> <blockquote> <p>Кстати, если этот механизм почему-то вам не помог, вы всегда можете явно задать имя хоста для прокси через настройку <code class="language-plaintext highlighter-rouge">Configuration.proxyHost = "my.comp.eu";</code></p> </blockquote> <p>См. <a href="https://github.com/selenide/selenide/pull/1970">PR 1970</a>.</p> <p><br /></p> <h3 id="upgrade-to-selenium-4.5.0">Обновились на Selenium 4.5.0</h3> <p>Из заметных изменений:</p> <ul> <li>удалили поддержку браузера Opera</li> <li>добавили альтернативную реализацию вебдрайвера на JDK 11 HTTP client вместо Netty client</li> <li>Добавили проверки на <code class="language-plaintext highlighter-rouge">disabled</code> в класс <code class="language-plaintext highlighter-rouge">Select</code> (больше не получится выбрать задизейбленный <code class="language-plaintext highlighter-rouge">option</code> в выпадающем списке)</li> <li>Убрали имя хоста из селениумовских эксепшенов <blockquote> <p>цуко, я просил об этом <a href="https://github.com/SeleniumHQ/selenium/issues/489">ещё в 2015 году</a>!!!</p> </blockquote> </li> </ul> <p>См. <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">ченджлог</a> и <a href="https://github.com/selenide/selenide/pull/1967">PR 1967</a>.</p> <p><br /></p> <h3 id="remove-opera-support">Выкинули поддержку Opera</h3> <p>Следствие предыдущего пункта. Селениум выкинул - и мы выкинули. Тестировать в опере не имеет особого смысла, т.к. это по сути тот же Chrome. Если очень хочется - можно, просто используйте chromedriver.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/1967">PR 1967</a>.</p> <p><br /></p> <h3 id="do-not-log-get-alias">Убрали <code class="language-plaintext highlighter-rouge">getAlias</code> из отчётов</h3> <p>Спасибо <a href="https://github.com/reserved-word">Reserved Word</a> за <a href="https://github.com/selenide/selenide/pull/1971">PR 1971</a>.</p> <p><br /></p> <h3 id="restore-setting-connection-timeout">Вернули настройку “connection timeout”</h3> <p>Это мало кому нужно, так что смело пропускайте.</p> <p class="small">Когда-то у нас было две настройки для http клиента вебдрайвера: “connection timeout” и “read timeout”. Первую пришлось убрать при обновлении на Selenium 4, потому что её там выпилили. Теперь её реанимировали в Selenium 4.5.0, ну и мы реанимировали.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/1977">PR 1977</a>.</p> <p><br /></p> <h3 id="update-dependencies">Обновили зависимости</h3> <ul> <li>LittleProxy from 2.0.12 to 2.0.13</li> <li>slf4j from 2.0.2 to 2.0.3</li> </ul> <p><br /></p> <h3 id="news">Новости</h3> <ul> <li>Доклад Сергея Брита <a href="https://www.youtube.com/watch?v=obsJWnBsYwk&amp;ab_channel=SQAANALYSTSECR">Selenide + Playwright Java = объединяй и властвуй</a> - конференция SQA Days EA, 01.10.2022</li> <li>Доклад Алексея Виноградова <a href="https://www.youtube.com/watch?v=MLxf9q9qXu4&amp;ab_channel=%D0%A2%D0%B5%D1%85%D0%BD%D0%BE%D0%BB%D0%BE%D0%B3%D0%B8%D0%B8%D0%B2%D0%9A%D0%BE%D0%BD%D1%82%D1%83%D1%80%D0%B5">Spinner-driven-development</a></li> </ul> <p><br /></p> <p>Айтишники, учите английский <a href="https://www.youtube.com/watch?v=laIGavOMcw8&amp;ab_channel=FoilArmsandHog">по ирландским комикам</a>!</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2022/10/07/selenide-6.9.0/ http://ru.selenide.org/2022/10/07/selenide-6.9.0 2022-10-07T00:00:00+00:00 Вышла Selenide 6.8.1 <p><br /></p> <h1 id="добре">Добре!</h1> <p>Ловите мини-багфикс <a href="https://github.com/selenide/selenide/milestone/165?closed=1">Selenide 6.8.1</a>.</p> <p>Это касается только тех, кто напрямую вызывает в своих тестах</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">new</span> <span class="nc">RemoteWebDriver</span><span class="o">(</span><span class="n">url</span><span class="o">,</span> <span class="n">options</span><span class="o">)</span> </code></pre></div></div> <p>и словил <code class="language-plaintext highlighter-rouge">NoClassDefFoundError</code> после обновления на <a href="/2022/09/24/selenide-6.8.0/">Selenide 6.8.0</a>.</p> <p><br /></p> <h3 id="pre-history">Предыстория</h3> <p>Что такое OpenTelemetry? Это какая-то штука, которую зачем-то добавили в Selenium 4, но людям забыли сообщить, зачем это вообще нужно и как этим пользоваться. Ну и по факту всем пофиг, никто не пользуется.</p> <p>Да и в самом селениде мы её явно выпилили в <a href="https://github.com/selenide/selenide/pull/1763">PR 1763</a>.</p> <blockquote> <p>Зависимость OpenTelemetry в Selenium - как специальная военная операция. Никто не знает, зачем она нужна.</p> </blockquote> <h3 id="the-problem">Проблема</h3> <p>В общем, у нормальных пользователей Селенида проблемы и не возникнет.</p> <p>НО если вы в своих тестах явно вызываете конструктор <code class="language-plaintext highlighter-rouge">new RemoteWebDriver(url, options)</code>, то он, к сожалению, требует зависимости OpenTelemetry. И после обновления на <a href="/2022/09/24/selenide-6.8.0/">Selenide 6.8.0</a> такие пользователи начали получать <code class="language-plaintext highlighter-rouge">NoClassDefFoundError</code>.</p> <p><br /></p> <h3 id="temporary-solution">Временное решение</h3> <p>Добавьте параметр <code class="language-plaintext highlighter-rouge">false</code> в конструктор: <code class="language-plaintext highlighter-rouge">new RemoteWebDriver(url, options, false)</code>. Этот <code class="language-plaintext highlighter-rouge">false</code> говорит “не используй телеметрию”.</p> <p><br /></p> <h3 id="restored-opentelemetry">Демобилизовали зависимость OpenTelemetry</h3> <p>В общем, мы по-быстрому выпустили Selenide 6.8.1, в котором вернули OpenTelemetry.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1965">issue 1965</a> и <a href="https://github.com/selenide/selenide/pull/1966">PR 1966</a>.</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2022/09/27/selenide-6.8.1/ http://ru.selenide.org/2022/09/27/selenide-6.8.1 2022-09-27T00:00:00+00:00 Вышла Selenide 6.8.0 <p><br /></p> <h1 id="недоброе-утро">Недоброе утро!</h1> <p>Пока в мире творится здипец, мы выпускаем релиз <a href="https://github.com/selenide/selenide/milestone/161?closed=1">Selenide 6.8.0</a>.<br /> Фич немного, больше обновление зависимостей.</p> <ul class="blogpost-menu"> <li><a href="#deep-shadow-selectors">Рекурсивный поиск по shadow dom</a></li> <li><a href="#add-page-without-class">Метод page() без параметров</a></li> <li><a href="#as-annotation">Аннотация @As</a></li> <li><a href="#news">Новости</a></li> </ul> <h3 id="deep-shadow-selectors">Рекурсивный поиск по shadow dom</h3> <p>Как вы знаете, в селениде <a href="/2020/03/18/selenide-5.10.0">есть возможность</a> искать элементы внутри shadow dom. И даже в нескольких вложенных shadow dom:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="n">shadowCss</span><span class="o">(</span><span class="s">"#reportButton"</span><span class="o">,</span> <span class="s">"#shadow-host"</span><span class="o">,</span> <span class="s">"#inner-shadow-host"</span><span class="o">)).</span><span class="na">click</span><span class="o">();</span> </code></pre></div></div> <p>Хорошо, что это возможно, но это по-прежнему требует ваших временных затрат на то, чтобы изучить dom и найти точные локаторы для всех этих теневых элементов.</p> <p>Теперь вы сможете сэкономить время с помощью нового метода <code class="language-plaintext highlighter-rouge">shadowDeepCss</code> - он ищет элемент во всех shadow root по всему dom.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="n">shadowDeepCss</span><span class="o">(</span><span class="s">"#reportButton"</span><span class="o">)).</span><span class="na">click</span><span class="o">();</span> </code></pre></div></div> <p>Естественно, остаётся риск, что такой “слишком широкий” поиск может найти и не тот элемент, если в ваших теневых областях есть несколько элементов в искомым локатором. В этом случае придётся вернуться к более точечному поиску.</p> <blockquote> <p>Как и в случае с базами данных и сосисками, “внутрь лучше не заглядывать” - там начинка из мудрёного джаваскрипта для поиска по дереву.</p> </blockquote> <p>См. <a href="https://github.com/selenide/selenide/issues/1946">issue 1946</a>.</p> <p>Спасибо</p> <ol> <li><a href="https://github.com/BorisOsipov">Boris Osipov</a> за <a href="https://github.com/selenide/selenide/pull/1947">PR 1947</a>, а также</li> <li><a href="https://github.com/Georgegriff">Georgegriff</a> за проект <a href="https://github.com/Georgegriff/query-selector-shadow-dom">query-selector-shadow-dom</a>, откуда мы этот код и спёрли.</li> </ol> <p><br /></p> <h3 id="add-page-without-class">Добавили метод <code class="language-plaintext highlighter-rouge">page()</code>, не требующий параметр <code class="language-plaintext highlighter-rouge">Class</code></h3> <p>Дорогие фанаты пэдж обжектов, садитесь поудобнее, это для вас. В вашей жизни наступает переломный момент.</p> <p>Теперь в метод <code class="language-plaintext highlighter-rouge">page(Class pageObjectClass)</code> больше не нужно передавать параметр <code class="language-plaintext highlighter-rouge">Class</code>. Да-да! Вместо</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">SelectsPage</span> <span class="n">page</span> <span class="o">=</span> <span class="n">page</span><span class="o">(</span><span class="nc">SelectsPage</span><span class="o">.</span><span class="na">class</span><span class="o">);</span> </code></pre></div></div> <p>вы сможете писать просто</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">SelectsPage</span> <span class="n">page</span> <span class="o">=</span> <span class="n">page</span><span class="o">();</span> </code></pre></div></div> <p>Раньше я думал, что Java так не умеет, но потом нашёл <a href="https://twitter.com/tagir_valeev/status/1262763570904719361">хак</a>.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/1961">PR 1961</a> и спасибо <a href="https://twitter.com/tagir_valeev">Тагиру Валееву</a> за хак.</p> <p><br /></p> <h3 id="as-annotation">Добавили аннотацию <code class="language-plaintext highlighter-rouge">@As</code></h3> <p>… для задания алиасов полям пэдж обжекта.</p> <h4 id="1-без-алиасов">1. Без алиасов</h4> <p>Если у вас есть пэдж обжект с аннотациями типа <code class="language-plaintext highlighter-rouge">@FindBy</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">PageObject</span> <span class="o">{</span> <span class="nd">@FindBy</span><span class="o">(</span><span class="n">xpath</span><span class="o">=</span><span class="s">"//table/div[3]/span[4]/h1"</span><span class="o">)</span> <span class="nc">SelenideElement</span> <span class="n">header</span><span class="o">;</span> <span class="o">}</span> </code></pre></div></div> <p>И тест типа <code class="language-plaintext highlighter-rouge">page.header.shouldBe(visible)</code>,</p> <p>То в отчётах он выглядит громоздко и непонятно:</p> <div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>| open | https://devclub.eu | PASS | | By.xpath: //table/div[3]/span[4]/h1 | should be(visible) | FAIL | </code></pre></div></div> <p>А если тест упадёт, то в сообщении не очень-то понятно, о каком элементе идёт речь:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Element</span> <span class="n">not</span> <span class="n">found</span> <span class="o">{</span><span class="nc">By</span><span class="o">.</span><span class="na">xpath</span><span class="o">:</span> <span class="c1">//table/div[3]/span[4]/h1}</span> </code></pre></div></div> <p>Люди часто хотят дать какое-то человеческое название этому элементу, чтобы не видеть в отчётах длинный непонятный xpath.</p> <h4 id="2-сопротивление">2. Сопротивление</h4> <p>Я всегда был против этого. Я считаю, что не только отчёты, но и сами тесты должны быть читабельными. Я за чистый код. Не нравится уродливый xpath - ну так измени его, а не прячь!</p> <p>Но потом я решил дать заднюю.</p> <blockquote> <p>Ведь если мы не дадим заднюю, то они могут дать заднюю, а вот если мы её дадим, они её не дадут. Заднюю никто не даст больше, кроме нас.</p> </blockquote> <p>Убедительно же! Поэтому в версии <a href="/2020/12/26/selenide-5.17.0/">Selenide 5.17.0</a> мы добавили метод <code class="language-plaintext highlighter-rouge">$.as("alias")</code>.</p> <h4 id="3-с-алиасами">3. С алиасами</h4> <p>А с этого релиза - ещё и можете навесить аннотацию <code class="language-plaintext highlighter-rouge">@As</code> на поля поля пэджобжектов.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">PageObject</span> <span class="o">{</span> <span class="nd">@As</span><span class="o">(</span><span class="s">"Large header"</span><span class="o">)</span> <span class="nd">@FindBy</span><span class="o">(</span><span class="n">tagName</span> <span class="o">=</span> <span class="s">"h1"</span><span class="o">)</span> <span class="nc">SelenideElement</span> <span class="n">header1</span><span class="o">;</span> <span class="o">}</span> </code></pre></div></div> <p>В отчётах он будет выглядеть короче:</p> <div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>| open | https://devclub.eu | PASS | | title | should be(visible) | FAIL | </code></pre></div></div> <p>А при падении теста будет легче понять, о каком элементе речь:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Element</span> <span class="s">"title"</span> <span class="n">not</span> <span class="n">found</span> <span class="o">{</span><span class="nc">By</span><span class="o">.</span><span class="na">xpath</span><span class="o">:</span> <span class="c1">//table/div[3]/span[4]/h1}</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1903">issue 1903</a> и <a href="https://github.com/selenide/selenide/pull/1956">PR 1956</a>.</p> <blockquote> <p>Не забывайте: врут все.</p> <p>Документация врёт, комментарии врут, пользователи врут. Рано или поздно соврёт и алиас. Локаторы поменяли, а алиас забыли. Или элемент скопировали, а алиас забыли поменять. И т.д.</p> <p>Отчёты - это хорошо, но в конечном итоге верить можно только коду.</p> </blockquote> <p><br /></p> <h3 id="update-dependencies">Обновили зависимости</h3> <ul> <li>BrowserUpProxy from 2.2.2 to 2.2.3</li> <li>LittleProxy from 2.0.11 to 2.0.12</li> <li>Netty from 4.1.80.Final to 4.1.82.Final</li> <li>slf4j from 2.0.0 to 2.0.2</li> <li>JUnit from 5.9.0 to 5.9.1 – см. <a href="https://junit.org/junit5/docs/5.9.1/release-notes/">release notes</a></li> </ul> <blockquote> <p>Объявлена частичная мобилизация зависимостей!</p> </blockquote> <p><br /></p> <h3 id="news">Новости</h3> <ul> <li>Продолжается серия от Dilpreet Johal - теперь <a href="https://dev.to/automationbro/upload-file-with-selenide-1f2a">Upload file with Selenide</a></li> <li><a href="https://sdet-tomaszbuga.medium.com/test-automation-framework-selenium-with-java-alchemy-or-translating-jira-with-selenide-with-e8831ebfe337">Alchemy or Translating JIRA with Selenide</a> от Tomasz Buga</li> <li>Вышла Java 19.</li> </ul> <h3 id="statistics">Статистика</h3> <p>Свежая статистика скачиваний Селенида нас только радует. Перевалили за 400 тыщ!</p> <center> <img src="/images/2022/09/selenide.downloads.png" width="800" /> </center> <p><br /></p> <p>Смотрите <a href="https://www.youtube.com/watch?v=m6TwkNAmI3A&amp;ab_channel=MasyanyaKuvaeva">Масяню!</a></p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2022/09/24/selenide-6.8.0/ http://ru.selenide.org/2022/09/24/selenide-6.8.0 2022-09-24T00:00:00+00:00 Вышла Selenide 6.7.4 <p><br /></p> <h1 id="привет">Привет!</h1> <p><br /> Я календарь перевернул, и снова релиз <a href="https://github.com/selenide/selenide/milestone/164?closed=1">Selenide 6.7.4</a>.</p> <p><br /></p> <h3 id="add-remote-read-setting">Добавили настройку <code class="language-plaintext highlighter-rouge">remoteReadTimeout</code></h3> <p>Ещё недавно <a href="https://www.youtube.com/watch?v=iIIsZRHya-w&amp;ab_channel=DEVCLUB.EU">я жаловался</a> на то, что в селениде и так слишком много настроек, но нам не оставили выбора.</p> <p>В общем, мы добавили ещё одну настройку <code class="language-plaintext highlighter-rouge">Configuration.remoteReadTimeout</code> (также известную как <code class="language-plaintext highlighter-rouge">-Dselenide.remoteReadTimeout</code>).</p> <p>Она пригодится тем, кто запускает браузер удалённо, но при этом браузеров на сервере не хватает, и приходится ждать в очереди. И поэтому дефалтового таймаута в 1.5 минуты оказывается недостаточно, чтобы элементарно открыть браузер.</p> <blockquote> <p>Лично я называю это адом на проекте, но кто мы такие, чтобы мешать людям добровольно жариться на сковородке…</p> </blockquote> <p>В общем, теперь вы можете указать какой угодно таймаут в билд-скриптах, в командой строке и т.п.</p> <p>Спасибо <a href="https://github.com/rodion-goritskov">Rodion Goritskov</a> за <a href="https://github.com/selenide/selenide/pull/1936">PR 1936</a>.</p> <p><br /></p> <p><br /></p> <h3 id="fix-dead-threads-watchdog">Исправили мини-косяк в “Dead threads watchdog”</h3> <p>Вы видели когда-нибудь <code class="language-plaintext highlighter-rouge">java.lang.IllegalStateException: Shutdown in progress</code> в логах?</p> <p>Значит, не обновились на <a href="/2022/08/14/selenide-6.7.2/">Selenide 6.7.2</a> :)</p> <p>В общем, обновляйтесь сразу на 6.7.4 - и всё будет <em>заерысь</em>.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1942">issue 1942</a> и <a href="https://github.com/selenide/selenide/pull/1943">PR 1943</a>.</p> <p><br /></p> <h3 id="update-dependencies">Обновили зависимости</h3> <ul> <li><a href="https://github.com/selenide/selenide/pull/1932">PR 1932</a> Bump Netty from 4.1.79 to 4.1.80</li> </ul> <p><br /></p> <h3 id="news">Новости</h3> <ul> <li><a href="https://blog.devgenius.io/selenide-101-in-5-minutes-2703086ee228">Selenide 101 in 5 minutes</a> by <a href="https://sophieer.medium.com/">Sophie R.</a></li> <li><a href="https://www.youtube.com/watch?v=0vlV8_4EDAg&amp;list=PL6AdzyjjD5HC4NJuc083bzFq86JekmASF&amp;ab_channel=AutomationBro-DilpreetJohal">Selenide Java Tutorial Series</a> by <a href="https://www.youtube.com/c/AutomationBro">Dilpreet Johal</a></li> <li><a href="https://mszeles.com/save-dozens-of-minutes-daily-during-writing-selenide-and-selenium-e2e-automated-tests-using-the-selenideium-element-inspector-chrome-extension">Selenideium Element Inspector</a> by <a href="https://hashnode.com/@mszeles">Miki Szeles</a></li> <li><a href="https://mszeles.com/selenium-javascript-python-c-cypress-testcafe-playwright-squish-selector-generation-has-been-added-to-selenideium-element-inspector-v20">Selenideium Element Inspector 2.0</a> by <a href="https://hashnode.com/@mszeles">Miki Szeles</a></li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2022/09/05/selenide-6.7.4/ http://ru.selenide.org/2022/09/05/selenide-6.7.4 2022-09-05T00:00:00+00:00 Вышла Selenide 6.7.3 <p><br /></p> <h1 id="привет">Привет!</h1> <p><br /> Вы читаете пресс-релиз <a href="https://github.com/selenide/selenide/milestone/163?closed=1">Selenide 6.7.3</a> в пиратском переводе.</p> <p>А что делать, <em>все хотят кушать</em>…</p> <p><br /></p> <h3 id="condition-partial-value">Добавили условие <code class="language-plaintext highlighter-rouge">partialValue</code></h3> <p>По аналогии с <code class="language-plaintext highlighter-rouge">$.shouldHave(partialText("Добрый ко"))</code> теперь появилась и <code class="language-plaintext highlighter-rouge">$.shouldHave(partialValue("cola"))</code>.</p> <p>Это если вы установили настройку <code class="language-plaintext highlighter-rouge">Configuration.textCheck = FULL_TEXT</code>, но хотите проверить значение какого-то инпута или textarea частично, а не полностью.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1923">issue 1923</a> и <a href="https://github.com/selenide/selenide/pull/1924">PR 1924</a>.</p> <p><br /></p> <h3 id="condition-tag-name">Добавили условие <code class="language-plaintext highlighter-rouge">tagName</code></h3> <p>Наверное, оно нечасто нужно, т.к. мы часто ищем элемент по тэгу, и уж потом проверяем другие атрибуты. Да и вообще, тэг - это внутренности, которые пользователь не видит, поэтому, может, и проверять его не нужно.</p> <p>Тем не менее, теперь вы можете проверять тэг:</p> <p><code class="language-plaintext highlighter-rouge">$(".btn-primary").shouldHave(tagName("button"));</code></p> <p>Или фильтровать коллекцию по тэгу:</p> <p><code class="language-plaintext highlighter-rouge">$$(byText("Submit!")).filterBy(tagName("button"));</code></p> <p>См. <a href="https://github.com/selenide/selenide/issues/1928">issue 1928</a> и <a href="https://github.com/selenide/selenide/pull/1929">PR 1929</a>.</p> <p><br /></p> <h3 id="check-select-tag">Проверяем, что элемент - <code class="language-plaintext highlighter-rouge">&lt;select&gt;</code></h3> <p>… в методах <code class="language-plaintext highlighter-rouge">$.getSelectedText()</code> и <code class="language-plaintext highlighter-rouge">getSelectedValue()</code>.</p> <p>Изначальная задумка этих методов была в том, чтобы найти выбранную опцию в селекте, и вернуть её текст или значение.</p> <p>Но</p> <ol> <li>во-первых, из названия это неочевидно (и поэтому мы переименовали их в <code class="language-plaintext highlighter-rouge">$.getSelectedOptionText()</code> и <code class="language-plaintext highlighter-rouge">getSelectedOptionValue()</code>)</li> <li>а во-вторых, эти методы можно было вызвать на любом другом элементе и получить непредсказуемое поведение.</li> </ol> <p>Теперь попытка вызова <code class="language-plaintext highlighter-rouge">$("div").getSelectedOptionText()</code> выкинет <code class="language-plaintext highlighter-rouge">IllegalArgumentException</code>.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/1934">PR 1934</a>.</p> <p><br /></p> <h3 id="update-dependencies">Обновили зависимости</h3> <ul> <li><a href="https://github.com/selenide/selenide/pull/1932">PR 1932</a> Bump webdrivermanager from 5.2.3 to 5.3.0</li> <li><a href="https://github.com/selenide/selenide/pull/1931">PR 1931</a> Bump slf4jVersion from 1.7.36 to 2.0.0</li> <li><a href="https://github.com/selenide/selenide/pull/1921">PR 1921</a> Bump browserup-proxy-core from 2.2.1 to 2.2.2</li> </ul> <p><br /></p> <h3 id="news">Новости</h3> <ul> <li>Selenide puzzler <a href="/2022/08/22/selenide-puzzler/">Логическое И или ИЛИ?</a></li> <li>Selenide упомянут в <a href="https://aglowiditsolutions.com/blog/top-java-frameworks/">Top Java Frameworks to Use in 2022</a></li> </ul> <p>И наконец, <strong>невиданное</strong>!</p> <ul> <li>Selenide упомянут на <a href="https://www.selenium.dev/ecosystem/">официальном сайте Selenium</a> в разделе “Экосистема”.</li> </ul> <p>Не может быть!</p> <p>Не прошло и 10 лет!</p> <p>А нет, прошло…</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2022/08/27/selenide-6.7.3/ http://ru.selenide.org/2022/08/27/selenide-6.7.3 2022-08-27T00:00:00+00:00 Selenide puzzler <p><br /></p> <h1 id="привет">Привет!</h1> <p>Вы любите пазлеры? Соскучались по пазлерам? В последний раз мы показывали пазлеры аж в 2017 году, кто не смотрел - <a href="https://www.youtube.com/watch?v=y-ZyxTWHH08&amp;ab_channel=Heisenbug">смотрим</a>!</p> <p>И вот наконец мы <a href="https://twitter.com/selenide/status/1560192824536088580">опубликовали в твиттере</a> новый пазлер:</p> <blockquote> <p>Одинаково ли работают эти строки? Или есть какая-то разница?</p> </blockquote> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="mi">1</span><span class="o">.</span> <span class="err">$</span><span class="o">(</span><span class="s">".btn"</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">visible</span><span class="o">,</span> <span class="n">enabled</span><span class="o">);</span> <span class="mi">2</span><span class="o">.</span> <span class="err">$</span><span class="o">(</span><span class="s">".btn"</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">visible</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">enabled</span><span class="o">);</span> </code></pre></div></div> <h3 id="варианты-ответов">Варианты ответов</h3> <p>Люди в твиттере и чатиках накидали разных вариантов:</p> <ul> <li>обе строчки работают одинаково (самый популярный ответ)</li> <li>первый случай: логическое or, второй: логический and</li> <li>Второй работает на %ожидание по умолчанию% дольше.</li> <li>Первый должен отработать с одним тайм-аутом, второй должен с двумя тайм-аутами</li> <li>в первом случае упадёт, если отсутствует любое из условий, во втором - если не visible, но enabled.</li> </ul> <h3 id="правильный-ответ">Правильный ответ</h3> <p>В большинстве случаев оба варианта работают одинаково.</p> <p>Оба варианта - это логическое AND. В обоих вариантах селенид проверит, что элемент соответствует обоим условиям.</p> <table> <tbody> <tr> <td> </td> <td><strong>enabled</strong></td> <td><strong>disabled</strong></td> </tr> <tr> <td><strong>видимый</strong></td> <td>ok</td> <td>nok</td> </tr> <tr> <td><strong>невидимый</strong></td> <td>nok</td> <td>nok</td> </tr> </tbody> </table> <p><br /></p> <p>Но есть нюанс.</p> <h3 id="нюанс">Нюанс</h3> <p>Разница проявится в том случае, если элемент соответствует условиям не сразу, а через какое-то время. Причём первому условию меньше, чем за 4 секунды, а второму - больше. (Допустим, visible он становится через 3.5 секунды, а enabled - ещё через 3.5 секунды).</p> <blockquote> <p>Всё дело в том, что таймаут (по умолчанию 4 секунды) есть у метода <code class="language-plaintext highlighter-rouge">shouldHave</code>, а у проверок (<code class="language-plaintext highlighter-rouge">visible</code>, <code class="language-plaintext highlighter-rouge">enabled</code>, <code class="language-plaintext highlighter-rouge">cssClass</code>, <code class="language-plaintext highlighter-rouge">text</code>) никакого таймаута нет - они просто умеют проверить, да или нет.</p> </blockquote> <h3 id="пример">Пример</h3> <p>Откроем для примера <a href="https://selenide.org/traffic-light.html">Светофор</a>. Светофор становится зелёным через 3.5 секунды, а текст на нём появляется ещё через 3.5 секунды.</p> <p>Первый вариант проверяет, что светофор удовлетворит обоим условиям в течение 4 секунд:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"#light"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">cssClass</span><span class="o">(</span><span class="s">"green"</span><span class="o">),</span> <span class="n">text</span><span class="o">(</span><span class="s">"GO!"</span><span class="o">));</span> <span class="c1">// таймаут 4 секунды</span> </code></pre></div></div> <p>И эта проверка упадёт, т.к. таймаут на эту проверку - 4 секунды, но элемент не приобретёт и цвет, и текст в течение 4 секунд.</p> <p>А второй вариант не упадёт:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#light"</span><span class="o">)</span> <span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">cssClass</span><span class="o">(</span><span class="s">"green"</span><span class="o">))</span> <span class="c1">// таймаут 4 секунды</span> <span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"GO!"</span><span class="o">));</span> <span class="c1">// и плюс ещё 4 секунды</span> </code></pre></div></div> <p>Первая проверка дождётся, пока элемент станет зелёным (и он станет в течение 4 секунд). После этого запустится вторая проверка и запустит новый таймаут с целью дождаться, пока у элемента появится текст. И он дождётся.</p> <p>Видимо, наиболее близкий к правильному был ответ “Первый должен отработать с одним тайм-аутом, второй должен с двумя тайм-аутами”.</p> <h3 id="ваши-пазлеры">Ваши пазлеры</h3> <p>Есть ли у вас свои пазлеры? Присылайте их нам, давайте будем отгадывать вместе!</p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2022/08/22/selenide-puzzler/ http://ru.selenide.org/2022/08/22/selenide-puzzler 2022-08-22T00:00:00+00:00 Вышла Selenide 6.7.2 <p><br /></p> <h1 id="привет">Привет!</h1> <p><br /> Мы выпустили мини-релиз <a href="https://github.com/selenide/selenide/milestone/162?closed=1">Selenide 6.7.2</a> с исправлением утечек памяти.</p> <p>Да-да, мы серьёзные ребята, у нас тоже бывают утечки.</p> <p>Но не пугайтесь, они некритические. Вряд ли кто-то из вас их вообще замечал.</p> <h3 id="fix-selenide-memory-leak">Исправили утечки с shutdown hooks в Selenide</h3> <p>Если в тесте много-много раз открывать и закрывать вебдрайвер</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">1000</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span> <span class="n">open</span><span class="o">(</span><span class="s">"about:blank"</span><span class="o">);</span> <span class="n">closeWebDriver</span><span class="o">();</span> <span class="o">}</span> </code></pre></div></div> <p>то расход памяти потихоньку растёт:</p> <p><img src="https://user-images.githubusercontent.com/279773/184475079-bbf8ee0f-d245-43ec-8e72-a010262e099c.png" style="width: 100%" alt="Memory consumption: before" /></p> <p><em>Красная линия, ты где?</em></p> <p>А вот что случилось на самом деле.</p> <p>Это просто сдетонировало несколько shutdown хуков, которые селенид складировал для каждого открытого вебдрайвера.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1917">issue 1917</a> и <a href="https://github.com/selenide/selenide/pull/1919">PR 1919</a>.</p> <p>После обновления на версию 6.7.2 память больше не растёт:</p> <p><img src="https://user-images.githubusercontent.com/279773/184499249-f6e1e3cb-bc88-4c04-8a7b-a080f3f08887.png" style="width: 100%" alt="Memory consumption: after" /></p> <p><em>Обновляемся на Selenide 6.7.2, выдыхаем и идём на пляж.</em></p> <p><br /></p> <h3 id="fix-little-proxy-memory-leak">Исправили утечку в LittleProxy</h3> <p>Мы обновились на версию LittleProxy 2.0.11, в которой была исправлена ещё одна утечка памяти.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/1918">PR 1918</a> и <a href="https://github.com/LittleProxy/LittleProxy/pull/141">PR 141</a></p> <p><br /></p> <h3 id="upgrade-to-selenium-4.4.0">Обновились на Selenium 4.4.0</h3> <p>в котором даже есть одно лично моё исправление, так-то! Которое, кстати, помогло нам исправить и следующую проблему.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/1913">PR 1913</a> и <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">Selenium changelog</a></p> <p><br /></p> <h3 id="fix-full-size-screenshot">Исправили плагин <code class="language-plaintext highlighter-rouge">full-size-screenshot</code></h3> <p>В нашем новом плагине <code class="language-plaintext highlighter-rouge">full-size-screenshot</code> была одна известная проблема (на самом деле вызванная багой в селениуме): если вы запускаете браузер удалённо и открываете несколько вкладок или окон, то селенид мог взять скриншот не с того окна.</p> <p>Эта ошибка была исправлена в Selenium 4.4.0, и соответственно, у нас она теперь тоже исправится.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/1920">PR 1920</a> и <a href="https://github.com/SeleniumHQ/selenium/pull/10811">PR 10811</a>.</p> <p><br /></p> <h3 id="news">Ссылки</h3> <ul> <li>Статья <a href="https://blogs.perficient.com/2022/06/22/working-efficiently-with-selenide-the-subset-of-selenium-webdriver/">Working Efficiently with Selenide</a> by Zainab Firdos, 22.06.2022</li> <li>Серия руководств <a href="https://dev.to/automationbro/selenide-tutorial-series-58p5">Selenide Tutorial Series</a> by Dilpreet Johal, 13.06.2022</li> <li>Видео-руководство <a href="https://www.youtube.com/watch?v=0vlV8_4EDAg&amp;t=318s&amp;ab_channel=AutomationBro-DilpreetJohal">Selenide Java Tutorial Series</a> by Automation Bro, 13.06.2022</li> <li>Статья <a href="https://hackernoon.com/how-to-start-your-friendship-with-selenide">How to Start Your Friendship with Selenide</a> by Miki Szeles, 30.03.2022</li> <li>Оффтопик: моё выступление на типа открытом микрофоне <a href="https://youtu.be/AOBEqZ0T51c">про поездки на конференции в Киев</a> - “Твой выход”, 23.07.2022, Таллинн</li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2022/08/14/selenide-6.7.2/ http://ru.selenide.org/2022/08/14/selenide-6.7.2 2022-08-14T00:00:00+00:00 Вышла Selenide 6.7.0 <p><br /></p> <h1 id="привет">Привет!</h1> <p><br /> У нас случился толстенький релиз <a href="https://github.com/selenide/selenide/milestone/154?closed=1">Selenide 6.7.0</a></p> <h3 id="holy-whole-string">Теперь <code class="language-plaintext highlighter-rouge">$.shouldHave(text)</code> может проверять текст целиком</h3> <p>Испокон веков команда <code class="language-plaintext highlighter-rouge">$.shouldHave(text)</code> проверяла не текст целиком, а только подстроку:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"freedom-to"</span><span class="nt">&gt;</span>Britney Spears<span class="nt">&lt;/div&gt;</span> </code></pre></div></div> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"#freedom-to"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Brit"</span><span class="o">));</span> <span class="c1">// was OK</span> </code></pre></div></div> <p>Когда-то это показалось удачной идеей, потому что веб-страничка часто содержит всякие левые символы (переводы строк, символы табуляции, непереносимые пробелы, множественные пробелы и т.п.).</p> <p>Но похоже, это всё-таки была неудачная идея, т.к. новички по умолчанию предполагают, что текст проверяется целиком, и выхватывают свою порцию WTF, когда обнаруживают, что все их проверки проверяли немного не то. :)</p> <p>А левые символы селенид научился правильно игнорировать (например, несколько пробелов/табов/переводов подряд эквивалентны одному пробелу).</p> <p>NB! Поскольку это изменение слишком уж кардинальное и наверняка сломает кучу ваших тестов, мы пока оставили по умолчанию старое поведение. А новое можно включить такой настройкой:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">Configuration</span><span class="o">.</span><span class="na">textCheck</span> <span class="o">=</span> <span class="no">FULL_TEXT</span><span class="o">;</span> </code></pre></div></div> <p>А когда вам нужно проверить именно подстроку, можете использовать новую проверку <code class="language-plaintext highlighter-rouge">partialText</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"#freedom-to"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">partialText</span><span class="o">(</span><span class="s">"ey Spear"</span><span class="o">))</span> </code></pre></div></div> <p>Возможно, мы включим этот режим по умолчанию в следующей мажорной версии Selenide 7.0.0 - а до тех пор <strong>вы можете поиграться и дать нам обратную связь</strong>.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1780">issue 1780</a> и <a href="https://github.com/selenide/selenide/pull/1783">PR 1783</a>.</p> <p><br /></p> <h3 id="full-size-screenshots">Научили Селенид делать большие скриншоты</h3> <p>Ну наконец-то!</p> <p>Как вы знаете, при падении теста селенид автоматически делает снимок экрана (скриншот), чтобы помочь вам понять, почему тест упал. По умолчанию вебдрайвер умеет снимать не всё окно браузера, а только видимую его часть. А самое важно часто оказывается за пределами экрана - тест валит какая-нибудь неактивная кнопка внизу экрана или всплывшее уведомление где-нибудь в углу.</p> <p>Теперь вы можете одной строчкой подключить плагин, который снимает скриншот с полным содержимым веб-странички:</p> <div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">testImplementation</span> <span class="s2">"com.codeborne:selenide-full-screenshot:6.7.0"</span> </code></pre></div></div> <p>P.S. Фича работает только для браузеров, поддерживающих CDP (Chrome, Edge и т.д.) и Firefox. Для остальных будут по-прежнему обычные скриншоты.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1799">issue 1799</a> и <a href="https://github.com/selenide/selenide/pull/1858">PR 1858</a>. Спасибо <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> за <a href="https://github.com/selenide/selenide/pull/1800">PR 1800</a>.</p> <p><br /></p> <h3 id="cache-lookup-annotation">Добавили кэширование элементов в пэдж обжектах</h3> <p>Как вы знаете, селенид поддерживает обычные селениумовские пэдж-обжекты с аннотациями <code class="language-plaintext highlighter-rouge">@FindBy</code>. Но вот аннотацию <code class="language-plaintext highlighter-rouge">@CacheLookup</code> селенид до сих пор не поддерживал - нам это казалось ненужной оптимизацией, ведь в тестах большая часть времени теряется вовсе не на поиск элементов.</p> <p>Но теперь вот поддерживаем, почему бы нет. Вдруг у кого-то всё настолько оптимизировано, что именно поиск элементов стал узким горлышком. Хотел бы я посмотреть на такой проект. :)</p> <p>Спасибо <a href="https://github.com/groov1kk">Ilya Koshaleu</a> за <a href="https://github.com/selenide/selenide/pull/1894">PR 1894</a>.</p> <p>P.S. Встаёт вопрос, а не надо ли добавить кэширование и для обычных <code class="language-plaintext highlighter-rouge">$</code> и <code class="language-plaintext highlighter-rouge">$$</code>. А как это оформить - параметром, настройкой? Новым методом?</p> <p><strong>Предлагайте ваши идеи!</strong></p> <p><br /></p> <h3 id="cancel-report-testng-annotation">Отменили аннотацию <code class="language-plaintext highlighter-rouge">@Report</code></h3> <p>Вот культура отмены добралась и до аннотаций!</p> <p>Это изменение касается любителей TestNG, которые использовали селенидовский отчёт. Для этого им надо было повесить на тесты две аннотации:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nd">@Listeners</span><span class="o">({</span><span class="nc">TextReport</span><span class="o">.</span><span class="na">class</span><span class="o">})</span> <span class="nd">@Report</span> <span class="kd">class</span> <span class="nc">MyTest</span> <span class="o">{...}</span> </code></pre></div></div> <p>Почему так сделали - это долгая история про корявые принципы работы листенеров в TestNG (вкратце: добавление аннотации листенера одному классу внезапно влияет на все остальные классы). Но теперь мы поняли, что систему можно упростить: аннотация <code class="language-plaintext highlighter-rouge">@Report</code> больше не нужна.</p> <p>А отчёт будет генерироваться для всех тестов, помеченных аннотацией <code class="language-plaintext highlighter-rouge">@Listeners({TextReport.class}</code> <strong>и их потомков</strong>.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1891">issue 1891</a> и <a href="https://github.com/selenide/selenide/pull/1909">PR 1909</a>.</p> <p><br /></p> <h3 id="decode-downloaded-file-name">Декодируем имя скачанного файла</h3> <p>Оказалось, что при скачивании файла имя файла в ответе сервера иногда бывает закодировано в Base64. А селенид считывал имя файла как есть. Теперь вот умеет расшифровывать и Base64.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1886">issue 1886</a> и <a href="https://github.com/selenide/selenide/pull/1889">PR 1889</a>.</p> <p><br /></p> <h3 id="restore-ie-support-set-value">Починили <code class="language-plaintext highlighter-rouge">$.setValue()</code> в IE</h3> <p>Оказалось, мы недавно сломали метод <code class="language-plaintext highlighter-rouge">$.setValue()</code> в Internet Explorer. Не то чтобы случайно: IE ведь официально отдал концы. Но жалобы были, и мы его вернули.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/1907">PR 1907</a>.</p> <p><br /></p> <h3 id="made-http-client-timeouts-public">Сделали публичным <code class="language-plaintext highlighter-rouge">HttpClientTimeouts</code></h3> <p>Но лишний раз туда лучше не лазать.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/1902">PR 1902</a>.</p> <p><br /></p> <h3 id="restore-set-value-string">Вернули тип параметра <code class="language-plaintext highlighter-rouge">String</code> для <code class="language-plaintext highlighter-rouge">$.setValue()</code></h3> <p>Лично у меня подгорает от того, что такая проблема вообще возникла.</p> <p>Подробности в <a href="https://github.com/selenide/selenide/issues/1885">issue 1885</a> и <a href="https://github.com/selenide/selenide/pull/1888">PR 1888</a>.</p> <p><br /></p> <h3 id="validate-file-extension">Добавили валидацию расширения файла</h3> <p>См. <a href="https://github.com/selenide/selenide/pull/1887">PR 1887</a>.</p> <p><br /></p> <h3 id="update-dependencies">Обновили зависимости</h3> <ul> <li>JUnit <a href="https://github.com/selenide/selenide/pull/1900">from 5.8.2 to 5.9.0</a></li> <li>WebDriverManager <a href="https://github.com/selenide/selenide/pull/1901">from 5.2.1 to 5.2.3</a></li> <li>Netty <a href="https://github.com/selenide/selenide/pull/1892">from 4.1.78.Final to 4.1.79.Final</a></li> <li>BrowserUpProxy <a href="https://github.com/selenide/selenide/pull/1895">from 2.2.0 to 2.2.1</a></li> <li>LittleProxy <a href="https://github.com/selenide/selenide/pull/1896">from 2.0.9 to 2.0.10</a></li> <li>ByteBuddy <a href="https://github.com/selenide/selenide/pull/1904">from 1.12.12 to 1.12.13</a></li> </ul> <p><br /></p> <h3 id="selenide-6.7.1">UPD Selenide 6.7.1</h3> <ul> <li>вернули параметр <code class="language-plaintext highlighter-rouge">Driver</code> в метод <code class="language-plaintext highlighter-rouge">SelenidePageFactory.findSelector()</code> - он используется в <code class="language-plaintext highlighter-rouge">selenide-appium</code>.</li> </ul> <p><br /></p> <h3 id="news">Новости</h3> <ul> <li><a href="https://github.com/iSYS-Software/SelenideReporter">Opinionated reporting framework for Selenide</a> от Ulrich Mayring</li> <li>Новая версия <a href="https://www.youtube.com/watch?v=C8MIGAjgVqE&amp;ab_channel=KVHigh-TechClub">Пацан накодил - пацан протестил</a> - Career Day, Минск, 04.06.2022</li> <li><a href="https://www.youtube.com/watch?v=-KGtZoFVzr8&amp;list=PL9Z-JgiTsOYRfoG_mcRBlTUIFPIknhQ6S">Extending open-source libraries: Selenide &amp; Selenium</a> - Selenium Conf, 30.07.2022</li> <li><a href="https://www.youtube.com/watch?v=SqiYAJfpQwY&amp;list=PLULFH3b6unlcUrwT9hJycTvAWPFqXZO4m&amp;ab_channel=QAClubLviv">Автоматизація з Selenide, ввідне заняття</a> by Роман Маринский</li> <li><a href="https://www.youtube.com/watch?v=-c5XT2v5gRY&amp;ab_channel=DEVCLUB.EE">Flaky Tests</a> - devclub.ee, Tallinn, 05.07.2022</li> <li>Оффтопик: моё выступление на типа открытом микрофоне <a href="https://youtu.be/AOBEqZ0T51c">про поездки на конференции в Киев</a> - “Твой выход”, 23.07.2022, Таллинн</li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2022/08/04/selenide-6.7.0/ http://ru.selenide.org/2022/08/04/selenide-6.7.0 2022-08-04T00:00:00+00:00 Вышла Selenide 6.6.6 <p><br /></p> <h1 id="добър-вечер">Добър вечер!</h1> <p><br /> У нас вышел ещё один мини-релиз <a href="https://github.com/selenide/selenide/milestone/160?closed=1">Selenide 6.6.6</a></p> <h3 id="remove-deprecated-capabilities">Удалили старые капабилити</h3> <p>Некоторые настройки вебдрайвера (которые селенид проставлял с испокон веков) были помечены как устаревшие, а с недавних пор селениум начал ругаться на нах в логах.</p> <p>Теперь селенид их больше не проставляет: <code class="language-plaintext highlighter-rouge">acceptSslCerts</code>, <code class="language-plaintext highlighter-rouge">handlesAlerts</code>, <code class="language-plaintext highlighter-rouge">javascriptEnabled</code>, <code class="language-plaintext highlighter-rouge">takesScreenshot</code>. Мы не забудем вас, друзья! Вы служили нам верой и правдой больше 10 лет.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1862">issue 1862</a>, <a href="https://github.com/selenide/selenide/issues/1866">issue 1866</a> и <a href="https://github.com/selenide/selenide/pull/1870">PR 1870</a>.</p> <p><br /></p> <h3 id="fix-clear-with-shortcut">Исправили ClearWithShortcut</h3> <p>… при работе с вебдрайвером, завёрнутым в листенеры. Редкая ситуация, не заморачивайтесь.</p> <p>Спасибо <a href="https://github.com/petroOv-PDFfiller">Petro Ovcharenko</a> за <a href="https://github.com/selenide/selenide/pull/1856">PR 1856</a>.</p> <p><br /></p> <h3 id="shorter-syntax-for-click">Добавили короткие варианты для вызова <code class="language-plaintext highlighter-rouge">$.click</code></h3> <p>Раньше, чтобы кликнуть со сдвигом или с кастомным таймаутом, приходилось писать довольно длинную строку:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">.</span><span class="na">click</span><span class="o">(</span><span class="n">withDefaultMethod</span><span class="o">().</span><span class="na">offset</span><span class="o">(</span><span class="mi">123</span><span class="o">,</span> <span class="mi">222</span><span class="o">));</span> <span class="err">$</span><span class="o">.</span><span class="na">click</span><span class="o">(</span><span class="n">withDefaultMethod</span><span class="o">().</span><span class="na">timeout</span><span class="o">(...));</span> </code></pre></div></div> <p>Теперь же можно написать короче:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">.</span><span class="na">click</span><span class="o">(</span><span class="n">withOffset</span><span class="o">(</span><span class="mi">123</span><span class="o">,</span> <span class="mi">222</span><span class="o">));</span> <span class="err">$</span><span class="o">.</span><span class="na">click</span><span class="o">(</span><span class="n">withTimeout</span><span class="o">(...));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/pull/1875">PR 1875</a>.</p> <p><br /></p> <h3 id="support-mobile-apps-in-webdriver-health-checker">Добавили поддержку мобилок при проверке, жив ли вебдрайвер</h3> <p>Мелкое исправление для <code class="language-plaintext highlighter-rouge">selenide-appium</code>. Чтобы проверить, а жив ли браузер, селенид периодически дёргает метод <code class="language-plaintext highlighter-rouge">WebDriver.getTitle()</code> (если вы переиспользуете один вебдрайвер между разными тестами).</p> <p>А тут обнаружилось, что метод <code class="language-plaintext highlighter-rouge">getTitle()</code> не поддерживается в Appium. Пришлось учесть.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1878">issue 1878</a> и <a href="https://github.com/selenide/selenide/pull/1879">PR 1879</a>.</p> <p><br /></p> <h3 id="fix-reopen-browser-on-fail">Исправили логику настройки <code class="language-plaintext highlighter-rouge">reopenBrowserOnFail</code></h3> <p>Ещё одно исправление для улучшения поддержки мобилок.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1880">issue 1880</a> и <a href="https://github.com/selenide/selenide/pull/1881">PR 1881</a>.</p> <p><br /></p> <h3 id="update-dependencies">Обновили зависимости</h3> <ul> <li>WebDriverManager <a href="https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md">с 5.2.0 на 5.2.1</a>.</li> <li>byteBuddyVersion <a href="https://github.com/selenide/selenide/pull/1872">с 1.12.11 на 1.12.12</a>.</li> </ul> <p><br /></p> <h3 id="release-selenide-appium-2.1.0">Выпустили selenide-appium 2.1.0</h3> <p>Немного улучшили там поддержку тестов на iOS.</p> <p>См. <a href="https://github.com/selenide/selenide-appium/blob/master/CHANGELOG">selenide-appium</a>.</p> <p><br /></p> <p><em>Этим релизом мы решили продемонстрировать мировому сообществу, что не препятствуем созданию автоматических тестов для мобильных приложений.</em></p> <p><em>Теперь слово за автоматизаторами.</em></p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2022/07/01/selenide-6.6.6/ http://ru.selenide.org/2022/07/01/selenide-6.6.6 2022-07-01T00:00:00+00:00 Вышла Selenide 6.6.4 <p><br /></p> <h1 id="приветос">Приветос!</h1> <p><br /> У нас вышел ещё один мини-релиз <a href="https://github.com/selenide/selenide/milestone/158?closed=1">Selenide 6.6.4</a>.</p> <h3 id="exact-texts-case-sensitive">Добавили условие <code class="language-plaintext highlighter-rouge">exactTextsCaseSensitive</code> для коллекций</h3> <p>В селениде есть несколько проверок для текстов коллекций:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$$</span><span class="o">(</span><span class="s">"li"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">texts</span><span class="o">(</span><span class="s">"foo"</span><span class="o">,</span> <span class="s">"bar"</span><span class="o">,</span> <span class="s">"baz"</span><span class="o">));</span> <span class="err">$$</span><span class="o">(</span><span class="s">"li"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">textsInAnyOrder</span><span class="o">(</span><span class="s">"foo"</span><span class="o">,</span> <span class="s">"bar"</span><span class="o">,</span> <span class="s">"baz"</span><span class="o">));</span> <span class="err">$$</span><span class="o">(</span><span class="s">"li"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">exactTexts</span><span class="o">(</span><span class="s">"foo"</span><span class="o">,</span> <span class="s">"bar"</span><span class="o">,</span> <span class="s">"baz"</span><span class="o">));</span> <span class="c1">// и др.</span> </code></pre></div></div> <p>Теперь к ним добавилась ещё одна:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$$</span><span class="o">(</span><span class="s">"li"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">exactTextsCaseSensitive</span><span class="o">(</span><span class="s">"foo"</span><span class="o">,</span> <span class="s">"bar"</span><span class="o">,</span> <span class="s">"baz"</span><span class="o">));</span> </code></pre></div></div> <p>Спасибо <a href="https://github.com/ben-nc2">Ben Heap</a> за <a href="https://github.com/selenide/selenide/pull/1861">PR 1861</a>.</p> <p><br /></p> <h3 id="selected-option-lazy-loaded">Сделали метод <code class="language-plaintext highlighter-rouge">$.getSelectedOption()</code> ленивым</h3> <p>По задумке, (почти) все методы Селенида <a href="https://github.com/selenide/selenide/wiki/Lazy-loading">должны быть ленивыми</a>.</p> <p>Например, просто вызов <code class="language-plaintext highlighter-rouge">$("#nope")</code> не должен падать, если элемента нет. Это позволяет писать отрицательные условия:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#nope"</span><span class="o">).</span><span class="na">shouldNot</span><span class="o">(</span><span class="n">exist</span><span class="o">);</span> </code></pre></div></div> <p>Оказалось, что метод <code class="language-plaintext highlighter-rouge">$("select").getSelectedOption()</code> не был ленивым и падал сразу, если селект ещё не успел подгрузиться и т.д.<br /> То есть вы в принципе не могли написать такую проверку:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kt">var</span> <span class="n">option</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"select#gender"</span><span class="o">).</span><span class="na">getSelectedOption</span><span class="o">();</span> <span class="c1">// падало на этом шаге</span> <span class="n">option</span><span class="o">.</span><span class="na">shouldNot</span><span class="o">(</span><span class="n">exist</span><span class="o">);</span> </code></pre></div></div> <p>Теперь мы исправили это недоразумение. <em>Лень победила!</em> См. <a href="https://github.com/selenide/selenide/issues/1581">issue 1581</a> и <a href="https://github.com/selenide/selenide/pull/1864">PR 1864</a>.</p> <p><br /></p> <h3 id="update-dependencies">Обновили зависимости</h3> <ul> <li>Netty <a href="https://github.com/selenide/selenide/pull/1857">с 4.1.77.Final на 4.1.78.Final</a>.</li> <li>BrowserUp proxy <a href="https://github.com/selenide/selenide/pull/1860">с 2.1.5 на 2.2.0</a>.</li> </ul> <p><br /></p> <h3 id="release-selenide-6.6.5">UPD Выпустили Selenide 6.6.5</h3> <p>И ещё мини-релиз <a href="https://github.com/selenide/selenide/milestone/159?closed=1">Selenide 6.6.5</a>.</p> <p>Обновили Selenium с 4.2.2 на 4.3.0.</p> <p><br /> <br /></p> <p><em>Это наш откровенный респонс на ваш откровенный реквест.</em></p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2022/06/20/selenide-6.6.4/ http://ru.selenide.org/2022/06/20/selenide-6.6.4 2022-06-20T00:00:00+00:00 Вышла Selenide 6.6.3 <p><br /></p> <h1 id="здравствуйте-друзья">Здравствуйте, друзья!</h1> <p><br /> Мы выпустили мини-релиз <a href="https://github.com/selenide/selenide/milestone/157?closed=1">Selenide 6.6.3</a>.</p> <h3 id="improve-click-timeout">Доработали таймаут для клика</h3> <p>В версии 6.6.0 мы добавили опциональный параметр - таймаут для метода <code class="language-plaintext highlighter-rouge">$.click()</code>.<br /> Но оказалось, что тот параметр решал <a href="/2022/06/08/selenide-6.6.0/#click-timeout">лишь половину проблемы</a>.</p> <p>Теперь мы исправили и вторую половину: вызов</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#slow-link"</span><span class="o">).</span><span class="na">click</span><span class="o">(</span><span class="n">usingDefaultMethod</span><span class="o">().</span><span class="na">timeout</span><span class="o">(</span><span class="n">ofSeconds</span><span class="o">(</span><span class="mi">8</span><span class="o">)));</span> </code></pre></div></div> <p>ждёт до 8 секунд как появления элемента <code class="language-plaintext highlighter-rouge">#slow-link</code>, так и последующей загрузки страницы.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1572">issue 1572</a> и <a href="https://github.com/selenide/selenide/pull/1853">PR 1853</a>.</p> <p><br /></p> <h3 id="selenide-6.6.2">Selenide 6.6.2</h3> <p>А чуть раньше мы выпустили мини-релиз <a href="https://github.com/selenide/selenide/milestone/156?closed=1">Selenide 6.6.2</a> с обновлением на Selenium 4.2.2</p> <p>См. <a href="https://github.com/selenide/selenide/pull/1851">PR 1851</a>.</p> <p><br /></p> <h3 id="selenide-6.6.1">Selenide 6.6.1</h3> <p>А чуть раньше мы выпустили мини-релиз <a href="https://github.com/selenide/selenide/milestone/155?closed=1">Selenide 6.6.1</a> с исправлением старой <a href="https://github.com/selenide/selenide/issues/1850">issue 1850</a>. Там мы вернули зависимость <code class="language-plaintext highlighter-rouge">byte-buddy</code>, без которой не работало добавление листенеров для вебдрайвера.</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2022/06/12/selenide-6.6.3/ http://ru.selenide.org/2022/06/12/selenide-6.6.3 2022-06-12T00:00:00+00:00 Вышла Selenide 6.6.0 <p><br /></p> <h1 id="здравствуйте-друзья">Здравствуйте, друзья!</h1> <p><br /> Мы выпустили релиз <a href="https://github.com/selenide/selenide/milestone/152?closed=1">Selenide 6.6.0</a>.</p> <h3 id="selenide-clear-with-shortcut">Появился новый плагин <code class="language-plaintext highlighter-rouge">selenide-clear-with-shortcut</code></h3> <p>В Selenide 6.5.0 мы поменяли реализацию <code class="language-plaintext highlighter-rouge">$.clear()</code> со стандартной селениумовской на шорткат (“Выделить всё” - Удалить). Оказалось, что этот шорткат не работал достаточно стабильно во всех браузерах, пришлось его доработать. Вроде стабилизировался, но стал медленнее, чем просто <code class="language-plaintext highlighter-rouge">WebElement.clear()</code>. А поскольку это не всем нужно, решили в конце концов в Селениде оставить старую добрую селениумовскую реализацию.</p> <p>А кому нужна очистка шорткатом - может подключить себе наш новый плагин:</p> <div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">testImplementation</span><span class="o">(</span><span class="s1">'com.codeborne:selenide:6.6.0'</span><span class="o">)</span> <span class="n">testImplementation</span><span class="o">(</span><span class="s1">'com.codeborne:selenide-clear-with-shortcut:6.6.0'</span><span class="o">)</span> </code></pre></div></div> <p>Зависимость <code class="language-plaintext highlighter-rouge">com.codeborne:selenide-clear-with-shortcut</code> переопределит метод <code class="language-plaintext highlighter-rouge">$.clear()</code> - а соответственно, и <code class="language-plaintext highlighter-rouge">$.setValue()</code>.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1497">issue 1497</a>, <a href="https://github.com/selenide/selenide/pull/1847">PR 1847</a> и <a href="https://github.com/selenide/selenide/pull/1838">PR 1838</a>.</p> <p><br /></p> <h3 id="fix-clear-in-safari">Исправили метод <code class="language-plaintext highlighter-rouge">$.clear()</code> в Safari</h3> <p>Внезапно выяснилось, что новый <code class="language-plaintext highlighter-rouge">$.clear()</code> не работал в Safari (кто его вообще использует?). <br /> Вроде починили. Делитесь опытом, как у вас, починилось?</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1819">issue 1819</a>, <a href="https://github.com/selenide/selenide/pull/1820">PR 1820</a>.</p> <p><br /></p> <h3 id="new-own-test-checks">Новые проверки для текста элемента</h3> <p>Добавили две новых проверки для “своего текста” (own text) элемента:</p> <ul> <li><code class="language-plaintext highlighter-rouge">$("#child_div1").shouldHave(ownTextCaseSensitive("Son"));</code></li> <li><code class="language-plaintext highlighter-rouge">$("#child_div1").shouldHave(exactOwnTextCaseSensitive("Son"))</code></li> </ul> <p>Спасибо <a href="https://github.com/kachurinaa">Kachurin Alexandr</a> за <a href="https://github.com/selenide/selenide/pull/1811">PR 1811</a> и <a href="https://github.com/selenide/selenide/pull/1812">PR 1812</a>.</p> <p><br /></p> <h3 id="click-timeout">Добавили метод <code class="language-plaintext highlighter-rouge">$.click()</code> с таймаутом</h3> <p>По умолчанию у метода <code class="language-plaintext highlighter-rouge">$.click()</code> стандартный селенидовский таймаут (который по умолчанию 4 секунды).<br /> Иногда этого недостаточно - например,</p> <ol> <li>Когда клик по ссылке ведёт на следующую страницу, которая грузится дольше 4 секунд.</li> <li>Когда элемент, по которому нужно кликнуть, ещё не появился на экране - и появляется больше, чем через 4 секунды.</li> </ol> <p>В этом релизе мы добавили таймаут методу <code class="language-plaintext highlighter-rouge">$.click()</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"#slow-link"</span><span class="o">).</span><span class="na">click</span><span class="o">(</span><span class="n">usingDefaultMethod</span><span class="o">().</span><span class="na">timeout</span><span class="o">(</span><span class="n">ofSeconds</span><span class="o">(</span><span class="mi">8</span><span class="o">)));</span> <span class="err">$</span><span class="o">(</span><span class="s">"#slow-link"</span><span class="o">).</span><span class="na">click</span><span class="o">(</span><span class="n">usingJavaScript</span><span class="o">().</span><span class="na">timeout</span><span class="o">(</span><span class="n">ofSeconds</span><span class="o">(</span><span class="mi">8</span><span class="o">)));</span> </code></pre></div></div> <p>Правда, этот параметр решает пока только первую проблему, но не вторую. В следующем релизе займёмся и второй. :)</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1572">issue 1572</a> и <a href="https://github.com/selenide/selenide/pull/1845">PR 1845</a>.</p> <p><br /></p> <h3 id="modal-timeout">Добавили таймаут методам <code class="language-plaintext highlighter-rouge">confirm()</code>, <code class="language-plaintext highlighter-rouge">dismiss()</code> и <code class="language-plaintext highlighter-rouge">prompt()</code></h3> <p>Издревле эти три метода позволяют работать с модальными джаваскриптовскими окошками (<code class="language-plaintext highlighter-rouge">alert</code>, <code class="language-plaintext highlighter-rouge">confirm</code>, <code class="language-plaintext highlighter-rouge">prompt</code>). Например,</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">confirm</span><span class="o">();</span> <span class="n">confirm</span><span class="o">(</span><span class="s">"Are you sure you want to delete all files?"</span><span class="o">);</span> </code></pre></div></div> <p>Но не было варианта с таймаутом - на тот случай, если алерт появляется не сразу, а больше, чем через 4 секунды. Теперь можно задать таймаут:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">confirm</span><span class="o">(</span><span class="n">withTimeout</span><span class="o">(</span><span class="n">ofSeconds</span><span class="o">(</span><span class="mi">2</span><span class="o">)));</span> <span class="n">confirm</span><span class="o">(</span><span class="n">withExpectedText</span><span class="o">(</span><span class="s">"Are you sure?"</span><span class="o">).</span><span class="na">timeout</span><span class="o">(</span><span class="n">ofSeconds</span><span class="o">(</span><span class="mi">2</span><span class="o">)));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1721">issue 1721</a> и <a href="https://github.com/selenide/selenide/pull/1846">PR 1846</a>.</p> <p><br /></p> <h3 id="fix-execute-javascript">Подправили метод <code class="language-plaintext highlighter-rouge">Driver.executeJavaScript()</code></h3> <p>…чтобы он работал и с “завёрнутым” вебдрайвером (т.е. когда на вебдрайвер навешаны листенеры).</p> <p>См. <a href="https://github.com/selenide/selenide/pull/1848">PR 1848</a>.</p> <p><br /></p> <h3 id="fix-checks-wording">Подправили формулировку некоторых проверок</h3> <p>… чтобы он звучали корректно по-английски. А именно:</p> <table> <thead> <tr> <th>В тесте</th> <th>В отчёте было</th> <th>В отчёте стало</th> </tr> </thead> <tbody> <tr> <td><code class="language-plaintext highlighter-rouge">$.should(appear)</code></td> <td>“Element should visible”</td> <td>“Element should be visible”</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">$.should(disappear)</code></td> <td>“Element should hidden”</td> <td>“Element should be hidden”</td> </tr> </tbody> </table> <p>См. <a href="https://github.com/selenide/selenide/pull/1840">PR 1840</a>.</p> <p><br /></p> <h3 id="restore-safari-options">Добавили опции для Safari</h3> <p>Выяснилось, что при открытии браузера Safari селенид терял почти все его настройки. Сломалось при переходе на Selenium 4. Починить это оказалось легко, но почему никто до сих пор не жаловался?</p> <p>Похоже, Safari всё-таки никто не использует. :)</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1836">issue 1836</a> и <a href="https://github.com/selenide/selenide/pull/1841">PR 1841</a>.</p> <p><br /></p> <h3 id="fix-testng-soft-asserts">Починили софт ассерты на TestNG</h3> <p>После обновления на TestNG 7.5 перестали правильно работать селенидовские софт ассерты. Если какая-то проверка падала, тест по-прежнему оставался зелёным.</p> <p>Пришлось откатиться до TestNG 7.4.0 и ждать исправления на той стороне.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1834">issue 1834</a> и <a href="https://github.com/selenide/selenide/pull/1843">PR 1843</a>.</p> <p><br /></p> <h3 id="update-dependencies">Обновили зависимости</h3> <ul> <li>Selenium <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">4.1.4 -&gt; 4.2.1</a>.</li> <li>WebDriverManager <a href="https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md">5.1.1 -&gt; 5.2.0</a></li> </ul> <p><br /></p> <h3 id="statistics">Статистика</h3> <p>Давно мы не публиковали статистика скачиваний Селенида</p> <center> <img src="/images/2022/06/selenide.downloads.png" width="800" /> </center> <p>Мы почти вернулись к рекордному показателю: 324 тысяч скачек за май.</p> <p><br /></p> <p>Не переключайтесь!</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2022/06/08/selenide-6.6.0/ http://ru.selenide.org/2022/06/08/selenide-6.6.0 2022-06-08T00:00:00+00:00 Вышла Selenide 6.5.0 <p><br /></p> <h1 id="здравствуйте-друзья">Здравствуйте, друзья!</h1> <p><br /> Мы выпустили релиз <a href="https://github.com/selenide/selenide/milestone/151?closed=1">Selenide 6.5.0</a>.</p> <h3 id="теперь-можно-маскировать-пароли-в-отчётах">Теперь можно маскировать пароли в отчётах</h3> <p>Иногда в автотестах приходится вбивать в поля пароли и другие секретные данные. И некоторые люди переживают, что эти данные потом видны в отчётах (Allure или TextReport). И просят их как-нибудь скрыть.</p> <p>Лично я не понимаю, почему кого-то должен волновать пароль от тестовой среды. (Вы же не используете одни и те же пароли во всех средах? Вы же не гоняете тесты на продакшине?)</p> <p>Но мы пошли навстречу пожеланиям переживающих, и теперь вы можете маскировать или заменять секретные данные:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"#password"</span><span class="o">).</span><span class="na">setValue</span><span class="o">(</span><span class="n">withText</span><span class="o">(</span><span class="s">"admin"</span><span class="o">).</span><span class="na">sensitive</span><span class="o">());</span> <span class="c1">// заменяет на звёздочки</span> <span class="err">$</span><span class="o">(</span><span class="s">"#username"</span><span class="o">).</span><span class="na">setValue</span><span class="o">(</span><span class="n">withText</span><span class="o">(</span><span class="s">"john"</span><span class="o">).</span><span class="na">withDisplayedText</span><span class="o">(</span><span class="s">"J* username"</span><span class="o">));</span> <span class="c1">// заменяет на "J* username"</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1768">issue 1768</a> и <a href="https://github.com/selenide/selenide/pull/1770">PR 1770</a>.</p> <p><br /></p> <h3 id="теперь-можно-легко-выбрать-дату-в-input-typedate">Теперь можно легко выбрать дату в <code class="language-plaintext highlighter-rouge">&lt;input type=date&gt;</code></h3> <p>Оказалось, что выбрать дату в селениуме не так-то просто.<br /> Если в вашем приложении есть элемент вида <code class="language-plaintext highlighter-rouge">&lt;input type=date&gt;</code>, то при клике в него разные браузеры открывают разные календарики, и при этом используют разные форматы даты. По идее они должны использовать формат из настроек пользователя, но на деле каждый браузер играет в свою игру.</p> <p>Всё это приводят к флейки тестам, которые могут работать на одном компьютере, но внезапно упасть на другом.</p> <p>В результате моего исследования я пришёл к выводу, что единственный надёжный способ выбрать дату - это установить значение в фиксированном формате <code class="language-plaintext highlighter-rouge">yyyy-mm-dd</code> через JavaScript. Похоже, это работает одинаково во всех ОС и браузерах.</p> <p>И теперь Селенид предоставляет такую возможность с помощью нового метода <code class="language-plaintext highlighter-rouge">withDate</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">LocalDate</span> <span class="n">birthday</span> <span class="o">=</span> <span class="nc">LocalDate</span><span class="o">.</span><span class="na">parse</span><span class="o">(</span><span class="s">"1979-12-31"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#birthday"</span><span class="o">).</span><span class="na">setValue</span><span class="o">(</span><span class="n">withDate</span><span class="o">(</span><span class="n">birthday</span><span class="o">));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1753">issue 1753</a> и <a href="https://github.com/selenide/selenide/pull/1770">PR 1770</a>.</p> <p><br /></p> <h3 id="теперь-метод-setvalue-поддерживает-react-vuejs-и-тп">Теперь метод <code class="language-plaintext highlighter-rouge">$.setValue("")</code> поддерживает React, Vue.js и т.п.</h3> <p>Давно замечено, что стандартный селениумовский метод <code class="language-plaintext highlighter-rouge">WebElement.clean()</code> (в частности, использующийся в селенидовском <code class="language-plaintext highlighter-rouge">$.setValue()</code>) не всегда правильно работает, когда имеют дело не с обычным <code class="language-plaintext highlighter-rouge">&lt;input&gt;</code>, а с обёрнутыми/обвязанными модными конструкциями, генерируемыми всякими современными JS-фреймворками типа React, Vue.js и прочей хипстоты.</p> <p>По идее мы это починили, ждём ваших отзывов.</p> <p>Теперь следующие методы реализованы не через стандартный селениумовский <code class="language-plaintext highlighter-rouge">WebElement.clear()</code>, а через нажатия комбинации клавиш:</p> <h4 id="1-method-clear">1. Method <code class="language-plaintext highlighter-rouge">$.clear()</code>:</h4> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">input</span><span class="o">.</span><span class="na">sendKeys</span><span class="o">(</span><span class="no">HOME</span><span class="o">,</span> <span class="n">chord</span><span class="o">(</span><span class="no">SHIFT</span><span class="o">,</span> <span class="no">END</span><span class="o">),</span> <span class="no">BACK_SPACE</span><span class="o">);</span> </code></pre></div></div> <h4 id="2-method-setvalue">2. Method <code class="language-plaintext highlighter-rouge">$.setValue("")</code>:</h4> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">input</span><span class="o">.</span><span class="na">sendKeys</span><span class="o">(</span><span class="no">HOME</span><span class="o">,</span> <span class="n">chord</span><span class="o">(</span><span class="no">SHIFT</span><span class="o">,</span> <span class="no">END</span><span class="o">),</span> <span class="no">BACK_SPACE</span><span class="o">,</span> <span class="no">TAB</span><span class="o">);</span> </code></pre></div></div> <p>Такой способ, похоже, работает во всех ОС и браузерах.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1497">issue 1497</a> и <a href="https://github.com/selenide/selenide/pull/1787">PR 1787</a>.</p> <p>Спасибо <a href="https://github.com/vinogradoff">Alexei Vinogradov</a> за исследование проблемы в <a href="https://github.com/selenide/selenide/pull/1499">PR 1499</a>.</p> <p><br /></p> <h3 id="убрали-двойное-событие-blur-и-change">Убрали двойное событие <code class="language-plaintext highlighter-rouge">blur</code> и <code class="language-plaintext highlighter-rouge">change</code></h3> <p>Из предыдущего изменения автоматически следует, что метод <code class="language-plaintext highlighter-rouge">$.setValue("blah")</code> вызывает события <code class="language-plaintext highlighter-rouge">blur</code> и <code class="language-plaintext highlighter-rouge">change</code> только единожды.</p> <p>А раньше метод <code class="language-plaintext highlighter-rouge">$.setValue("blah")</code> работал в два шага и вызывал их дважды:</p> <ul> <li>Шаг 1. <code class="language-plaintext highlighter-rouge">$.clear()</code> // вызывало <code class="language-plaintext highlighter-rouge">blur</code> и <code class="language-plaintext highlighter-rouge">change</code></li> <li>Шаг 2. <code class="language-plaintext highlighter-rouge">$.sendKeys("blah")</code> // ещё раз вызывало <code class="language-plaintext highlighter-rouge">blur</code> и <code class="language-plaintext highlighter-rouge">change</code></li> </ul> <p>И события на первом шаге иногда приводили к неожиданным эффектам - например, исчезанию самого поля.<br /> См. <a href="https://github.com/selenide/selenide/issues/960">issue 960</a>.</p> <p><br /></p> <h3 id="вызываем-событие-blur-на-предыдущем-элементе">Вызываем событие <code class="language-plaintext highlighter-rouge">blur</code> на предыдущем элементе</h3> <p>В предыдущем пулреквесте заодно сделали так, что метод <code class="language-plaintext highlighter-rouge">$.setValue("blah")</code> вызывает событие <code class="language-plaintext highlighter-rouge">blur</code> на предыдущем активном элементе. Как минимум это помогло исправить некоторые наши флейки тесты. Надеемся, поможет и вам.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1784">issue 1784</a> и <a href="https://github.com/selenide/selenide/commit/593e6fc900500d9">commit 593e6fc9005</a>.</p> <p><br /></p> <h3 id="теперь-методы-setvalue-и-append-проверяют-что-элемент-не-выключен">Теперь методы <code class="language-plaintext highlighter-rouge">$.setValue()</code> и <code class="language-plaintext highlighter-rouge">$.append()</code> проверяют, что элемент не выключен</h3> <p>Точнее, что элемент не находится в состоянии “disabled” или “readonly”.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1523">issue 1523</a> и <a href="https://github.com/selenide/selenide/pull/1787">PR 1787</a>.</p> <p><br /></p> <h3 id="добавили-новые-проверки-interactable-и-editable">Добавили новые проверки “interactable” и “editable”</h3> <p>Эти проверки уже существовали и использовались раньше внутри Селенида, но не торчали наружу. А теперь и вы сможете их использовать:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"input[type=file]"</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">interactable</span><span class="o">);</span> <span class="c1">// interactable = visible OR "opacity: 0"</span> <span class="err">$</span><span class="o">(</span><span class="s">"input"</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">editable</span><span class="o">);</span> <span class="c1">// editable = interactable AND enabled AND !readonly</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1523">issue 1523</a> и <a href="https://github.com/selenide/selenide/pull/1787">PR 1787</a>.</p> <p><br /></p> <h3 id="метод-downloadfolder-дожидается-полной-загрузки-файла">Метод <code class="language-plaintext highlighter-rouge">$.download(FOLDER)</code> дожидается полной загрузки файла</h3> <p>Британские учёные обнаружили, что иногда флейки тесты вызваны тем, что файл скачивается довольно медленно, и селенид успевает обнаружить и скопировать к себе файл, который уже появился в <code class="language-plaintext highlighter-rouge">C:\Downloads</code>, но ещё не полностью загружен.</p> <p>Теперь селенид ждёт, пока в <code class="language-plaintext highlighter-rouge">C:\Downloads</code> исчезнут все файлы “<em>.crdownload” (для хрома) и “</em>.part” (для фаерфокса). Это временный файл, создаваемый браузером на короткий период, пока скачивается файл.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1779">issue 1779</a>, <a href="https://github.com/selenide/selenide/pull/1804">PR 1804</a> и <a href="https://github.com/selenide/selenide/pull/1769">PR 1769</a>.</p> <p><br /></p> <h3 id="добавили-метод-stream-для-коллекций">Добавили метод <code class="language-plaintext highlighter-rouge">stream()</code> для коллекций</h3> <p>Точнее, метод <code class="language-plaintext highlighter-rouge">$$.stream()</code> существовал и раньше, но в версии <a href="/2022/01/10/selenide-6.2.0/">6.2.0</a> был помечен как deprecated. Теперь вместо него есть на выбор два не-deprecated метода:</p> <ul> <li><code class="language-plaintext highlighter-rouge">$$.asFixedIterable().stream()</code></li> <li><code class="language-plaintext highlighter-rouge">$$.asDynamicIterable().stream()</code></li> </ul> <p>См. <a href="https://github.com/selenide/selenide/issues/1773">issue 1773</a> и <a href="https://github.com/selenide/selenide/pull/1774">PR 1774</a>.</p> <p><br /></p> <h3 id="удалили-встроенную-селениумовскую-телеметрию-opentelemetry">Удалили встроенную селениумовскую телеметрию (OpenTelemetry)</h3> <p>Я так понимаю, эта телеметрия появилась в Selenium 4. Не знаю, зачем она вообще нужна, но кому-то мешала (потому, что у него уже была какая-то своя телеметрия). Ну и нам было проще её удалить, чем поддерживать обе.</p> <p>Спасибо <a href="https://github.com/zzz">Petro Ovcharenko</a> и <a href="https://github.com/zzz">Aliaksandr Rasolka</a> за <a href="https://github.com/selenide/selenide/pull/1763">PR 1763</a>.</p> <p><br /></p> <h3 id="обновили-зависимости">Обновили зависимости</h3> <ul> <li>Selenium <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">4.1.3 -&gt; 4.1.4</a>.</li> <li>WebDriverManager <a href="https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md">5.1.0 -&gt; 5.1.1</a></li> <li>Netty <a href="https://netty.io/news/2022/04/12/4-1-76-Final.html">4.1.75.Final -&gt; 4.1.76.Final</a></li> <li>Netty <a href="https://netty.io/news/2022/05/06/2-1-77-Final.html">4.1.76.Final -&gt; 4.1.77.Final</a></li> <li>LittleProxy <a href="https://github.com/LittleProxy/LittleProxy/releases">2.0.7 -&gt; 2.0.9</a></li> </ul> <p>Кстати, проект LittleProxy переехал в отдельную <a href="https://github.com/LittleProxy/LittleProxy">организацию на гитхабе</a>, и теперь я его главный мейнтейнер. Не то, чтобы я был фанатом проксей, но он используется в селениде, и поддерживать его как-то надо…</p> <p><br /></p> <h1 id="upd-selenide-651">UPD Selenide 6.5.1</h1> <p>Небольшое обновление <a href="https://github.com/selenide/selenide/milestone/153?closed=1">Selenide 6.5.1</a>:</p> <ul> <li><a href="https://github.com/selenide/selenide/issues/1808">#1808</a> Починили <code class="language-plaintext highlighter-rouge">$.clear()</code>, чтобы он не жмякал таб - см. <a href="https://github.com/selenide/selenide/pull/1809">PR #1809</a></li> <li><a href="https://github.com/selenide/selenide/pull/1806">#1806</a> Обновились с browserup-proxy-core 2.1.4 на 2.1.5</li> </ul> <p><br /></p> <h1 id="upd-selenide-652">UPD Selenide 6.5.2</h1> <p><a href="https://github.com/selenide/selenide/issues/1497">#1497</a> Починили <code class="language-plaintext highlighter-rouge">$.clear()</code> на свежем фаерфоксе: теперь жмякаем “Ctrl+A -&gt; Delete” вместо “Home -&gt; Shift+A -&gt; Delete”. См. <a href="https://github.com/selenide/selenide/pull/1838">PR #1838</a>.</p> <p><br /></p> <h3 id="новости">Новости</h3> <p>Отдельный привет всем, кто ждал, что же тут будет в конце пресс-релиза. ;)</p> <p>А будет моя презентация с последнего фестиваля TechTrain.</p> <iframe src="https://docs.google.com/presentation/d/e/2PACX-1vRIZ4w6bc7wTjWVkHTfCdevRGMo81VRIgNQ-V5Bzy1FV9ldG3jtexEXnbJ79CMtOTKhao36VHKZlfs6/embed?start=false&amp;loop=true&amp;delayms=3000" frameborder="0" width="960" height="569" allow="fullscreen" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe> <p><br /></p> <p>Видео с TechTrain будет через несколько месяцев, а пока можете посмотреть похожее <a class="video" href="//www.youtube.com/watch?v=iIIsZRHya-w">видео из девклуба</a>. Оно немного другое, ибо ориентировано на другую аудиторию, но общее представление получить можно.</p> <p><br /></p> <p>Не переключайтесь!</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2022/05/17/selenide-6.5.0/ http://ru.selenide.org/2022/05/17/selenide-6.5.0 2022-05-17T00:00:00+00:00 Вышла Selenide 6.4.0 <p><br /></p> <h1 id="здравствуйте-друзья">Здравствуйте, друзья!</h1> <p><br /> Мы выпустили релиз <a href="https://github.com/selenide/selenide/milestone/145?closed=1">Selenide 6.4.0</a>.</p> <h3 id="показываем-и-алиас-и-локатор-при-падении-тестов">Показываем и алиас, и локатор при падении тестов</h3> <p>Как вы знаете, в Селениде с помощью метода <code class="language-plaintext highlighter-rouge">as</code> можно задавать элементам “алиас”, или понятное имя. Это полезно в тех случаях, когда нет хорошего локатора, и приходится писать какой-нибудь длинный сложный xpath, который потом в отчётах сложно читать.</p> <p>Например:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">$x</span><span class="o">(</span><span class="s">"/long/ugly/xpath/div[2]/span[3]/li[4]"</span><span class="o">).</span><span class="na">as</span><span class="o">(</span><span class="s">"Login button"</span><span class="o">).</span><span class="na">click</span><span class="o">();</span> </code></pre></div></div> <p>И у нас всегда была дилемма: нужно ли</p> <ol> <li>показывать только алиас (плюс: легко читается, минус: не видно селектора - вдруг он нужен?)</li> <li>показывать и алиас, и селектор (плюс: видно селектор, минус: трудно читается).</li> </ol> <p><br /></p> <p>И вот наконец мы поняли, как правильно. Начиная с версии 6.4.0, селенид будет:</p> <ol> <li>В отчётах на каждом шаге показывать только алиас (коротко, легко читается)</li> <li>А вот при падении теста в сообщение об ошибке добавлять и алиас, и локатор (длинно, зато будет вся необходимая информация для изучения падения).</li> </ol> <p>Например, вышеупомянутая строка в отчётах будет выглядеть вот так:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>+----------------------+--------------------+------------+------------+ | Element | Subject | Status | ms. | +----------------------+--------------------+------------+------------+ | Login button | click() | FAIL | 206 | +----------------------+--------------------+------------+------------+ </code></pre></div></div> <p>А сообщение об ошибке - так:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Element</span> <span class="s">"Login button"</span> <span class="n">not</span> <span class="n">found</span> <span class="o">{</span><span class="nc">By</span><span class="o">.</span><span class="na">xpath</span><span class="o">:</span> <span class="o">/</span><span class="kt">long</span><span class="o">/</span><span class="n">ugly</span><span class="o">/</span><span class="n">xpath</span><span class="o">[</span><span class="mi">1</span><span class="o">][</span><span class="mi">2</span><span class="o">][</span><span class="mi">3</span><span class="o">]}</span> <span class="nl">Expected:</span> <span class="n">exist</span> <span class="nl">Screenshot:</span> <span class="o">...</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1765">issue 1765</a> и <a href="https://github.com/selenide/selenide/pull/1766">PR 1766</a>.</p> <p><br /></p> <h3 id="добавили-пробелы-в-селенидовском-отчёте">Добавили пробелы в селенидовском отчёте</h3> <p>Например, вышеупомянутый отчёт раньше выглядел так:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>+---------------------+-------------------+------------+------------+ |Element |Subject | Status | ms. | +---------------------+-------------------+------------+------------+ |open |https://google.com/some-long-url.html?q=selenide|PASS |1285 | |Login button |click() | FAIL | 206 | +---------------------+-------------------+------------+------------+ </code></pre></div></div> <p>Проблема была как минимум в том, что вокруг URL слева и справа вплотную прилегают символы <code class="language-plaintext highlighter-rouge">|</code>, так что его невозможно быстро выделить двойным кликом. Теперь вокруг URL и других значений будут пробелы. Заодно отчёт и покрасивее стал.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1764">issue 1764</a> и <a href="https://github.com/selenide/selenide/pull/1767">PR 1767</a>.</p> <p><br /></p> <h3 id="обновились-на-selenium-413">Обновились на Selenium 4.1.3</h3> <p>См. <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">ченджлог Selenium</a> и <a href="https://github.com/selenide/selenide/pull/1759">PR 1759</a>.</p> <p><br /></p> <p><br /></p> <h1 id="важно">ВАЖНО</h1> <p>Меня зовут Андрей Солнцев, я 10 лет делаю библиотеку Selenide и делюсь опытом на конференциях.<br /> Просто так, бесплатно. Я у вас никогда ничего за это не просил.</p> <p>А теперь я прошу всего лишь услышать меня. Вот как вижу ситуацию я - в целом неглупый человек, мнение которого, надеюсь, стало для многих из вас авторитетным за эти 10 лет.</p> <p><br /></p> <p>Россия начала <strong>войну в Украине</strong>. Бессмысленную и бесчеловечную.</p> <p>Там сейчас под бомбёжками, под обстрелами сидят мирные люди, которые никому ничего плохого не сделали.<br /> В том числе и пользователи селенида.</p> <ul> <li>Те, перед которыми я многократно выступал на конференциях.</li> <li>Те, которых я слушал и учился.</li> <li>Те, которые помогали развивать селенид, и результатами работы которых пользуются люди во всём мире, в том числе и России. Пользуетесь лично вы.</li> </ul> <p>Это тяжело признать, об этом тяжело думать, от этого ужаса хочется спрятаться - но такова реальность.</p> <p><br /> Я не знаю, как это остановить.<br /> Но я прошу вас хотя бы <em>не поддерживать это</em>.<br /> Я призываю вас не верить этой <em>чудовищной лжи</em> про нацистов, расширение НАТО, фейки и т.п.<br /> Я прошу вас оставаться людьми.</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2022/04/07/selenide-6.4.0/ http://ru.selenide.org/2022/04/07/selenide-6.4.0 2022-04-07T00:00:00+00:00 Вышла Selenide 6.3.0 <p><br /></p> <h1 id="здравствуйте-друзья">Здравствуйте, друзья!</h1> <p><br /> Мы зарелизили <a href="https://github.com/selenide/selenide/milestone/143?closed=1">Selenide 6.3.0</a>.</p> <p>Приготовьте бутеры и погнали!</p> <p><br /></p> <h1 id="добавили-метод-switchtoframetimeout-с-кастомным-таймаутом">Добавили метод <code class="language-plaintext highlighter-rouge">switchTo().frame(timeout)</code> с кастомным таймаутом</h1> <p>В селениде есть метод <code class="language-plaintext highlighter-rouge">switchTo().frame(name)</code> для переключения между фреймами. Как всегда, со встроенной ожидалкой и другими плюшками. Но что, если фрейм грузится дольше, чем таймаут по умолчанию (4 секунды)?</p> <p>Теперь вы можете передать дополнительный параметр <code class="language-plaintext highlighter-rouge">Duration</code> - таймаут для переключения во фрейм:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">switchTo</span><span class="o">().</span><span class="na">frame</span><span class="o">(</span><span class="s">"ifrm"</span><span class="o">);</span> <span class="c1">// по умолчанию ждёт до 4 секунд</span> <span class="n">switchTo</span><span class="o">().</span><span class="na">frame</span><span class="o">(</span><span class="s">"ifrm"</span><span class="o">,</span> <span class="nc">Duration</span><span class="o">.</span><span class="na">ofSeconds</span><span class="o">(</span><span class="mi">6</span><span class="o">));</span> <span class="c1">// а вот теперь до 6 секунд</span> </code></pre></div></div> <p>Спасибо <a href="https://github.com/donesvad">@donesvad</a> за <a href="https://github.com/selenide/selenide/pull/1722">PR 1722</a>.</p> <p><br /></p> <h1 id="добавили-селекторы-bytagandtext-и-withtagandtext">Добавили селекторы <code class="language-plaintext highlighter-rouge">byTagAndText</code> и <code class="language-plaintext highlighter-rouge">withTagAndText</code></h1> <p>До сих пор в селениде были методы для поиска элементов по тексту:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">Selectors</span><span class="o">.*;</span> <span class="err">$</span><span class="o">(</span><span class="n">byText</span><span class="o">(</span><span class="s">"Hello world"</span><span class="o">)).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Hello World"</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="n">withText</span><span class="o">(</span><span class="s">"Hello"</span><span class="o">)).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Hello World"</span><span class="o">));</span> </code></pre></div></div> <p>Иногда этого мало: когда элементов с таким текстом несколько, и хочется из них выбрать только один - с нужным тэгом.</p> <p>Теперь и для этого есть методы:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">Selectors</span><span class="o">.*;</span> <span class="err">$</span><span class="o">(</span><span class="n">byTagAndText</span><span class="o">(</span><span class="s">"h1"</span><span class="o">,</span> <span class="s">"Hello world"</span><span class="o">)).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Hello World"</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="n">withTagAndText</span><span class="o">(</span><span class="s">"h1"</span><span class="o">,</span> <span class="s">"Hello"</span><span class="o">)).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Hello World"</span><span class="o">));</span> </code></pre></div></div> <p>Спасибо <a href="https://github.com/maurizio-lattuada">Maurizio Lattuada</a> за <a href="https://github.com/selenide/selenide/issues/1650">issue 1650</a> и <a href="https://github.com/selenide/selenide/pull/1651">PR 1651</a>.</p> <p><br /></p> <h1 id="исправили-ошибку-в-bytextcaseinsensitive">Исправили ошибку в <code class="language-plaintext highlighter-rouge">byTextCaseInsensitive</code></h1> <p>Теперь этот селектор игнорирует множественные пробелы и переводы строк в начале и конце текста (как и каноничный <code class="language-plaintext highlighter-rouge">byText</code>).</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1723">issue 1723</a> и <a href="https://github.com/selenide/selenide/pull/1724">PR 1724</a>.</p> <p><br /></p> <h1 id="добавили-записи-webdriver-create-в-webdriver-close-в-отчёт">Добавили записи “webdriver create” в “webdriver close” в отчёт</h1> <p>Если вы используете селенидовский <code class="language-plaintext highlighter-rouge">TextReport</code> или плагин <code class="language-plaintext highlighter-rouge">AllureSelenide</code>, вы привыкли в конце каждого теста видеть отчёт, в котором видны все действия: открыли страничку - нашли элемент - кликнули и т.д.</p> <p>Теперь там добавилась запись, когда был запущен сам вебдрайвер. И когда закрыт. Иногда эта информация может быть полезна при отладке различных проблем с тестами.</p> <p>Спасибо <a href="https://github.com/petroOv-PDFfiller">Petro Ovcharenko</a> за <a href="https://github.com/selenide/selenide/pull/1715">PR 1715</a>.</p> <p><br /></p> <h1 id="исправили-переопределение-селениумовского-таймаута">Исправили переопределение селениумовского таймаута</h1> <p>В <a href="/2021/06/08/selenide-5.22.0/">Selenide 5.22.0</a> мы сделали хак, который менял дефалтовый селениумовский таймаут для общения с вебдрайвером с дичайших 3 часов до 2 минут.</p> <p>Однако выяснилось, что при обновлении на Selenium 4 этот хак сломался (как и положено всем хакам). Теперь мы его реанимировали.</p> <p>Напоминаю, теперь при общении между тестами и вебдрайвером таймаут такой:</p> <ul> <li>таймаут на соединение - 10 секунд</li> <li>таймаут на чтение - 1.5 минуты</li> </ul> <p>См. <a href="https://github.com/selenide/selenide/commit/cf02da5">commit cf02da5</a>.</p> <p><br /></p> <h1 id="убрали-двойное-заворачивание-ошибок-element-not-found-друг-в-друга">Убрали двойное заворачивание ошибок “Element not found” друг в друга</h1> <p>См. <a href="https://github.com/selenide/selenide/issues/1705">issue 1705</a> и <a href="https://github.com/selenide/selenide/pull/1706">PR 1706</a>.</p> <p><br /></p> <h1 id="добавили-поддержку-типа-аутентификации-bearer">Добавили поддержку типа аутентификации <code class="language-plaintext highlighter-rouge">BEARER</code></h1> <p>В селениде давно уже есть способ аутентификации с разными типами:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">open</span><span class="o">(</span><span class="s">"/basic-auth/hello"</span><span class="o">,</span> <span class="no">BASIC</span><span class="o">,</span> <span class="s">"scott"</span><span class="o">,</span> <span class="s">"tiger"</span><span class="o">);</span> </code></pre></div></div> <p>но точно правильно работал только тип <code class="language-plaintext highlighter-rouge">BASIC</code>. Остальные особо никто не проверял. :)</p> <p>Оказалось, что тип <code class="language-plaintext highlighter-rouge">BEARER</code> не работал. Теперь вот работает (а остальные по-прежнему никто не проверял :)).</p> <p>Использовать так:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">open</span><span class="o">(</span><span class="s">"/bearer-token-auth/hello"</span><span class="o">,</span> <span class="no">BEARER</span><span class="o">,</span> <span class="k">new</span> <span class="nc">BearerTokenCredentials</span><span class="o">(</span><span class="s">"token-123"</span><span class="o">));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/pull/1714">PR 1714</a>.</p> <p><br /></p> <h1 id="теперь-пустые-настройки-типа-selenideremote-считаются-незаданными">Теперь пустые настройки типа <code class="language-plaintext highlighter-rouge">selenide.remote</code> считаются незаданными</h1> <p>Это должно чутка упростить жизнь девопсам.<br /> При настройках всяких там джобов и пайплайнов на CI сервере, часто приходится использовать переменные для задания настроек селенида:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-Dselenide.remote=${env.GRID_URL} </code></pre></div></div> <p>И если в какой-нибудь среде переменной <code class="language-plaintext highlighter-rouge">GRID_URL</code> не окажется, то селенид грохнется, т.к. попытается использовать пустой урл для <code class="language-plaintext highlighter-rouge">selenide.remote</code>.</p> <p>Так было раньше. А теперь селенид будет считать, что <code class="language-plaintext highlighter-rouge">selenide.remote</code> просто не задан, и продолжить работать как обычно.</p> <p>См. <a href="https://github.com/vinogradoff">Alexei Vinogradov</a> за <a href="https://github.com/selenide/selenide/issues/1656">issue 1656</a> и <a href="https://github.com/BorisOsipov">Boris Osipov</a> за <a href="https://github.com/selenide/selenide/pull/1663">PR 1663</a>.</p> <p><br /></p> <h1 id="обновились-на-selenium-412">Обновились на Selenium 4.1.2</h1> <p>После обновления на Selenium 4.1.2 у многих слетела версия Guava. Селенид явно определяет нужную версию Guava, так что вас эта проблема затронуть не должна. Но если что, убедитесь, что в вашем проекте никакой там градловский или мавеновский плагин не переопределяет версию Guava. Старый добрый <a href="/2020/11/17/why-proxy-does-not-work-in-selenoid/">пост про зависимости</a> в помощь.</p> <p>См. <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">ченджлог Selenium</a> и <a href="https://github.com/selenide/selenide/pull/1719">PR 1719</a>.</p> <p><br /></p> <h1 id="upd-selenide-631">UPD Selenide 6.3.1</h1> <p>Небольшое обновление <a href="https://github.com/selenide/selenide/milestone/146?closed=1">Selenide 6.3.1</a>:</p> <ul> <li><a href="https://github.com/selenide/selenide/issues/1731">#1731</a> вернули возможность использовать софт ассерты в TestNG в методах <code class="language-plaintext highlighter-rouge">@Before*</code> и <code class="language-plaintext highlighter-rouge">@After*</code> (ранее мы их случайно запретили в Selenide 6.2.0) - см. <a href="https://github.com/selenide/selenide/pull/1732">PR #1732</a></li> <li><a href="https://github.com/selenide/selenide/pull/1729">#1729</a> Обновились с Netty 4.1.73.Final на 4.1.74.Final</li> </ul> <p><br /></p> <h1 id="upd-selenide-632">UPD Selenide 6.3.2</h1> <p>Ещё обновление <a href="https://github.com/selenide/selenide/milestone/147?closed=1">Selenide 6.3.2</a>:</p> <ul> <li><a href="https://github.com/selenide/selenide/pull/1733">#1733</a> Запилили костыль для баги селениума <a href="https://github.com/SeleniumHQ/selenium/issues/10345">10345</a>, из-за которой метод <code class="language-plaintext highlighter-rouge">FirefoxDriver.close()</code> валится после обновления на Firefox 97.</li> <li><a href="https://github.com/selenide/selenide/pull/1736">#1736</a> Обновились с BrowserUpProxy 2.1.3 на 2.1.4</li> <li><a href="https://github.com/selenide/selenide/pull/1611">#1611</a> Обновили версию Java с 8 до 17.</li> </ul> <p>А вот тут давайте остановимся поподробнее. Теперь проект Selenide собирается на Java 17, но бинарники <code class="language-plaintext highlighter-rouge">selenide-*.jar</code> по-прежнему собираются для Java 8. Поэтому</p> <ul> <li>разработчики селенида могут использовать все последние фичи языка Java, а</li> <li>пользователи селенида могут по-прежнему запускать свои тесты на Java 8 (хоть мы и советуем обновить джавушку, конечно).</li> </ul> <p>А стало это возможным благодаря инструменту <a href="https://github.com/bsideup/jabel">Jabel</a> и лично <a href="https://github.com/bsideup"> Sergei Egorov</a>, придумавшему этот изящный хак (а ещё причастному к <a href="https://github.com/testcontainers/testcontainers-java">TestContainers</a> и <a href="https://www.atomicjar.com/">AtomicJar</a>).</p> <p><br /></p> <h1 id="upd-selenide-633">UPD Selenide 6.3.3</h1> <p>Ещё обновление <a href="https://github.com/selenide/selenide/milestone/148?closed=1">Selenide 6.3.3</a>:</p> <ul> <li>#1737 позволили переопределять настройки Firefox для скачивания файлов</li> <li>#1740 обновились на WebDriverManager 5.1.0</li> </ul> <p><br /></p> <h1 id="upd-selenide-634">UPD Selenide 6.3.4</h1> <p>Ещё обновление <a href="https://github.com/selenide/selenide/milestone/149?closed=1">Selenide 6.3.4</a>:</p> <ul> <li>#1746 показываем ожидаемый атрибут при падении <code class="language-plaintext highlighter-rouge">$.shouldHave(attribute(...))</code>.</li> <li>#1748 исправили имя модуля в сгенерированных бинарниках селенида</li> </ul> <p><br /></p> <h1 id="upd-selenide-635">UPD Selenide 6.3.5</h1> <p>Ещё обновление <a href="https://github.com/selenide/selenide/milestone/150?closed=1">Selenide 6.3.5</a>:</p> <ul> <li><a href="https://github.com/selenide/selenide/issues/1755">#1755</a> починили скачивание файлов через прокси, если ответ сервера закодирован - см. <a href="https://github.com/selenide/selenide/pull/1756">PR #1756</a></li> </ul> <p><br /></p> <h1 id="новости">Новости</h1> <ul> <li>Мы создали группу в LinkedIn <a href="https://www.linkedin.com/groups/9154550/">Selenide User Group</a>!</li> <li>Пост от Miklós Szeles <a href="https://www.linkedin.com/pulse/selenium-selenide-mikl%25C3%25B3s-szeles/">Selenium or Selenide?</a></li> <li>Селенид попал в подборку <a href="https://qameta.io/blog/5-testing-automation-tools/">5 Testing Automation Tools</a> в блоге компании Qameta Software (это которая Allure Report)</li> <li>Селенид попал в подборку <a href="https://hackernoon.com/top-java-libraries-for-automation-testing-in-2022">Top Java Libraries for Automation Testing in 2022</a></li> <li>Пост <a href="https://blog.knoldus.com/selenide-concise-ui-test-in-java/">про Селенид</a> в блоге компании Knoldus</li> <li>Пост <a href="https://medium.com/@gaveen0513/selenide-the-software-that-doesnt-need-documentation-cda8535cb7e6">The software that doesn’t need documentation</a> от Gaveen Nayanajith</li> <li>Пост <a href="https://mszeles.com/selenide-i-think-this-is-the-beginning-of-a-beautiful-friendship">начало прекрасной дружбы</a> от Miklós Szeles</li> </ul> <p><br /></p> <h4 id="я-думаю-это-начало-прекрасной-дружбы">Я думаю, это начало прекрасной дружбы!</h4> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2022/02/07/selenide-6.3.0/ http://ru.selenide.org/2022/02/07/selenide-6.3.0 2022-02-07T00:00:00+00:00 Вышла Selenide 6.2.0 <p><br /></p> <h1 id="с-новым-годом">С новым годом!</h1> <p><br /> Мы зарелизили <a href="https://github.com/selenide/selenide/milestone/140?closed=1">Selenide 6.2.0</a>.</p> <p>Давайте посмотрим, что нам приготовил первый релиз в новом году.</p> <p>Наливайте чай и погнали! <br /></p> <h1 id="добавили-ссылку-click-to-see-difference-для-большинства-селенидовских-ошибок">Добавили ссылку “&lt;Click to see difference&gt;” для большинства селенидовских ошибок</h1> <p>Как вы помните, в <a href="/2021/09/28/selenide-5.25.0/">Selenide 5.25.0</a> мы добавили поддержку OpenTest4J, в результате чего у селенидовских ошибок в IDE появилась ссылочка “&lt;Click to see difference&gt;”, позволяющая удобно посмотреть различия между ожидаемым и актуальным значением.</p> <p>Но тогда мы всё порефакторить не успели, и ссылочка появилась не у всех типов ошибок. <br /> А теперь должна появиться у всех.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1589">issue 1589</a> и <a href="https://github.com/selenide/selenide/pull/1676">PR 1676</a>.</p> <p><br /></p> <h1 id="заменили-iterator-на-asdynamiciterable-и-asfixediterable">Заменили <code class="language-plaintext highlighter-rouge">$$.iterator()</code> на <code class="language-plaintext highlighter-rouge">$$.asDynamicIterable()</code> и <code class="language-plaintext highlighter-rouge">$$.asFixedIterable()</code></h1> <blockquote> <p><em>Ух какую старую болячку мы исправили!</em> <em>Ну молодцы же!</em></p> </blockquote> <p>Есть в селениде метод <code class="language-plaintext highlighter-rouge">$$</code> для коллекции элементов. Возвращает он объект класса <code class="language-plaintext highlighter-rouge">ElementsCollection</code>.<br /> Изначально у него должен был быть только один метод <code class="language-plaintext highlighter-rouge">$$.shouldHave(&lt;условие&gt;)</code>. Хочешь проверить коллекцию элементов на соответствие какому-то условию - передай нужное условие. Не нашёл готового условия - напиши своё, благо это легко.</p> <h3 id="the-ошибка">The ошибка</h3> <p>Но в те давние времена случилось так, что я наследовал класс <code class="language-plaintext highlighter-rouge">ElementsCollection</code> от <code class="language-plaintext highlighter-rouge">AbstractList&lt;SelenideElement&gt;</code>. Об этом решении я неоднократно жалел впоследствии.</p> <p>Что же случилось, спросите вы? А случилось то, что люди начали абьюзить коллекции как не в себя.</p> <ul> <li>Например, начали итерировать все элементы в коллекции (это <em>случайно</em> стало возможным благодаря наследованию от <code class="language-plaintext highlighter-rouge">AbstractList</code>).</li> <li>И ещё люди ожидают, что элементы в коллекции будут постоянно обновляться, ведь до сих пор селенид автоматически обновлял любые веб-элементы.</li> <li>Помимо сомнительного тест-дизайна, это вызвало ещё и проблемы с производительностью, ведь на каждом шаге итерации селенид должен загрузить заново всю коллекцию элементов. А это может быть медленно, особенно есть элементов много или коллекция фильтруется: <code class="language-plaintext highlighter-rouge">$$("div").filter(visible).filterBy(text("Hello"))</code>.</li> </ul> <h3 id="the-дилемма">The дилемма</h3> <p>Получилась дилемма:</p> <ul> <li>одним хотелось, чтобы селенид при итерировании перегружал элементы каждый раз, ведь это позволяет не получать <code class="language-plaintext highlighter-rouge">StaleElementException</code>, когда элементы на странице исчезают и появляются;</li> <li>а другим хотелось, наоборот, чтобы селенид не перегружал элементы при итерировании, ведь это ускоряет тест на больших коллекциях.</li> </ul> <p>Какой вариант ни выберешь - всем не угодишь.</p> <h3 id="the-решение">The решение</h3> <p>И наконец мы придумали, как решить эту дилемму. Случайно унаследованные от <code class="language-plaintext highlighter-rouge">AbstractList</code> методы типа <code class="language-plaintext highlighter-rouge">$$.iterator()</code> мы пометили как <code class="language-plaintext highlighter-rouge">@Deprecated</code>. Вместо них предлагаем вам два метода, из которых вы сами сможете выбрать согласно вашим потребностям:</p> <ul> <li><code class="language-plaintext highlighter-rouge">$$.asDynamicIterable()</code> - перегружает элементы коллекции при итерировании. Может быть медленным на больших коллекциях.</li> <li><code class="language-plaintext highlighter-rouge">$$.asFixedIterable()</code> - не перегружает элементы при итерировании. Он быстрее, но не получает обновлений, если элементы удаляются или добавляются во время итерирования.</li> </ul> <h3 id="the-совет">The совет</h3> <p>Какой из них я вам советую?</p> <p>НИКАКОЙ! :)</p> <p>Напоминаю, что в хорошем тесте, скорее всего, не должно быть циклов, условий и т.п.<br /> Вы должны точно знать, сколько элементов ожидается на странице, и какие свойства должны быть у каждого из них! <em>Просто проверьте эти свойства.</em></p> <p>Вместо итерирования всегда лучше написать <a href="https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/CustomCollectionConditionTest.java">свой <code class="language-plaintext highlighter-rouge">CollectionCondition</code></a>. Благо это легко.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/797">issue 797</a> и <a href="https://github.com/selenide/selenide/pull/1688">PR 1688</a>.</p> <p><br /></p> <h1 id="исправили-softassert-чтобы-он-не-валил-тест">Исправили SoftAssert, чтобы он не валил тест</h1> <p>в довольно редкой ситуации:</p> <ol> <li>если софт ассерт listener/rule/extension добавлен к тесту, но</li> <li>софт ассерты <strong>выключены</strong>, и</li> <li>внутри теста кидается и тут же ловится ошибка (try/catch).</li> </ol> <p>Вообще в такой ситуации надо исправлять сам тест. :(</p> <p>И всё же. До сих пор селенидовский софт ассерт валил тест, потому что в ходе теста была ошибка, и листенер это заметил. А теперь листенер стал чуть умнее и тест не валит.</p> <blockquote> <p><em>Уф, ну и проблемки вы иногда подкидываете, дорогие пользователи… :)</em></p> </blockquote> <p>См. <a href="https://github.com/selenide/selenide/issues/1646">issue 1646</a> и <a href="https://github.com/selenide/selenide/pull/1680">PR 1680</a>.</p> <p><br /></p> <h1 id="исправили-софт-ассерты-чтобы-они-включали-все-падения">Исправили софт ассерты, чтобы они включали все падения</h1> <p>Ещё одна редкая проблема с софт ассертами. Представьте ситуацию:</p> <ol> <li>Софт ассерты включены;</li> <li>В ходе теста случились какие-то селенидовские ошибки (пойманы софт ассерт листенером);</li> <li>А также в ходе теста случилась какая-то другая ошибка (банальный <code class="language-plaintext highlighter-rouge">NPE</code> или <code class="language-plaintext highlighter-rouge">assertEquals(2, 3)</code>).</li> </ol> <p>В этом случае селенидовский софт ассерт листенер валил тест (что правильно), но показывал только селенидовские ошибки (п. 2) и терял “другую” ошибку (п.3).</p> <p>Теперь листенер стал умнее, и показывает все ошибки.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1661">issue 1661</a> и <a href="https://github.com/selenide/selenide/pull/1679">PR 1679</a>.</p> <p><br /></p> <h1 id="добавили-локаторы-к-некоторым-селенидовским-ошибкам">Добавили локаторы к некоторым селенидовским ошибкам</h1> <p>Мелочь, но стоит упомянуть.</p> <p>Мы добавили селектор к некоторым селенидовским ошибкам.<br /> Например, там, где селенид раньше кидал такую ошибку:</p> <blockquote> <p>“Invalid element state: Cannot change invisible element”</p> </blockquote> <p>Теперь он будет кидать такую:</p> <blockquote> <p>“Invalid element state [.btn.btn-primary]: Cannot change invisible element”</p> </blockquote> <p><br /></p> <h1 id="обновили-browserupproxy-с-212-на-213">Обновили BrowserUpProxy с 2.1.2 на 2.1.3</h1> <p>Важно отметить, что версия 2.1.3 - это форк оригинального BrowserUpProxy. Автор объявил о прекращении поддержки, добровольцы переняли инициативу и зарелизили версию 2.1.3 <a href="https://github.com/browserup/browserup-proxy/issues/388#issuecomment-1004097733">из форка</a>.</p> <p>Будем следить за ситуацией. В идеале хорошо бы перейти с BrowserUpProxy на mitmproxy. Есть добровольцы?</p> <p>См. <a href="https://github.com/selenide/selenide/pull/1678">PR 1678</a>.</p> <p><br /></p> <h1 id="обновили-testng-с-740-на-75">Обновили TestNG с 7.4.0 на 7.5</h1> <p>Список изменений <a href="https://github.com/cbeust/testng/blob/7.5/CHANGES.txt">внушительный</a>.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/1682">PR 1682</a>.</p> <p><br /></p> <p>С Новым Годом, друзья!<br /> Стабильных тестов вам и красивых отчётиков!</p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2022/01/10/selenide-6.2.0/ http://ru.selenide.org/2022/01/10/selenide-6.2.0 2022-01-10T00:00:00+00:00 Вышла Selenide 6.1.1 <p><br /></p> <h1 id="tere-hommikust">TERE HOMMIKUST!</h1> <p><br /> Мы зарелизили <a href="https://github.com/selenide/selenide/milestone/141?closed=1">Selenide 6.1.1</a>.</p> <p>В этом маленьком релизе мы исправили сразу пачку проблем с настройками браузеров.<br /> Они все всплыли после обновления на Selenium 4, в котором <code class="language-plaintext highlighter-rouge">ChromeOptions</code> и другие <code class="language-plaintext highlighter-rouge">Capabilities</code> были серьёзно переработаны.</p> <p>Ну вот, теперь мы погрузились в тему и разом все проблемы исправили.</p> <p><br /></p> <h1 id="early-conflicts-detection">Раннее обнаружение конфликтов</h1> <p>Если вы попытаетесь открыть хром с настройками файерфокса:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Configuration</span><span class="o">.</span><span class="na">browser</span> <span class="o">=</span> <span class="s">"chrome"</span><span class="o">;</span> <span class="nc">Configuration</span><span class="o">.</span><span class="na">browserCapabilities</span><span class="o">.</span><span class="na">setCapability</span><span class="o">(</span><span class="no">FIREFOX_OPTIONS</span><span class="o">,</span> <span class="k">new</span> <span class="nc">FirefoxOptions</span><span class="o">());</span> </code></pre></div></div> <p>то Селенид версии 5.x ругался, а Селенид 6.0.x перестал ругаться. Теперь мы ругань восстановили, и вы снова увидите старое доброе</p> <blockquote> <p>IllegalArgumentException: Conflicting browser name: ‘chrome’ vs. ‘firefox’</p> </blockquote> <p>См. <a href="https://github.com/selenide/selenide/issues/1591">issue 1591</a> и <a href="https://github.com/selenide/selenide/pull/1642">PR 1642</a>.</p> <p><br /></p> <h1 id="merging-chrome-arguments">Слияние аргументов хрома</h1> <p>Если вы попытаетесь задать хрому, например, полноэкранный режим или язык:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">ChromeOptions</span> <span class="n">options</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ChromeOptions</span><span class="o">();</span> <span class="n">options</span><span class="o">.</span><span class="na">addArguments</span><span class="o">(</span><span class="s">"--start-fullscreen"</span><span class="o">,</span> <span class="s">"--start-incognito"</span><span class="o">);</span> <span class="n">options</span><span class="o">.</span><span class="na">setExperimentalOption</span><span class="o">(</span><span class="s">"prefs"</span><span class="o">,</span> <span class="nc">ImmutableMap</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="s">"intl.accept_languages"</span><span class="o">,</span> <span class="s">"de_DE"</span><span class="o">));</span> <span class="nc">Configuration</span><span class="o">.</span><span class="na">browserCapabilities</span> <span class="o">=</span> <span class="n">chromeOptions</span><span class="o">;</span> <span class="n">open</span><span class="o">(</span><span class="s">"https://codeborne.com"</span><span class="o">;)</span> </code></pre></div></div> <p>то эти настройки терялись в Selenide 6.0.x Теперь мы их восстановили.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1626">issue 1626</a>, <a href="https://github.com/selenide/selenide/issues/1630">issue 1630</a> и <a href="https://github.com/selenide/selenide/issues/1631">issue 1631</a>.</p> <p>Исправление в <a href="https://github.com/selenide/selenide/pull/1642">PR 1642</a>.</p> <p><br /></p> <h1 id="wrapping-browser-capabilities">ВАЖНО</h1> <p>Если вы использовали <code class="language-plaintext highlighter-rouge">Configuration.browserCapabilities</code>, то с большой вероятностью заворачивали их в <code class="language-plaintext highlighter-rouge">DesiredCapabilities</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">ChromeOptions</span> <span class="n">options</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ChromeOptions</span><span class="o">();</span> <span class="n">options</span><span class="o">.</span><span class="na">addArguments</span><span class="o">(...);</span> <span class="nc">DesiredCapabilities</span> <span class="n">caps</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">DesiredCapabilities</span><span class="o">();</span> <span class="n">caps</span><span class="o">.</span><span class="na">setCapability</span><span class="o">(</span><span class="nc">ChromeOptions</span><span class="o">.</span><span class="na">CAPABILITY</span><span class="o">,</span> <span class="n">options</span><span class="o">);</span> <span class="nc">Configuration</span><span class="o">.</span><span class="na">browserCapabilities</span> <span class="o">=</span> <span class="n">caps</span><span class="o">;</span> </code></pre></div></div> <p>Так вот, теперь этот <strong>код нужно упростить</strong>, чтобы настройки больше не терялись:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">ChromeOptions</span> <span class="n">options</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ChromeOptions</span><span class="o">();</span> <span class="n">options</span><span class="o">.</span><span class="na">addArguments</span><span class="o">(...);</span> <span class="nc">Configuration</span><span class="o">.</span><span class="na">browserCapabilities</span> <span class="o">=</span> <span class="n">options</span><span class="o">;</span> </code></pre></div></div> <p><br /></p> <h1 id="webdriver-provider-parameter-type">Поменяли тип параметра в <code class="language-plaintext highlighter-rouge">WebDriverProvider</code></h1> <p>… с <code class="language-plaintext highlighter-rouge">DesiredCapabilities</code> на просто <code class="language-plaintext highlighter-rouge">Capabilities</code>.</p> <p>Для вас почти ничего не меняется. Если вы используете в своих тестах <code class="language-plaintext highlighter-rouge">WebDriverProvider</code>, просто поменяйте <code class="language-plaintext highlighter-rouge">DesiredCapabilities</code> на <code class="language-plaintext highlighter-rouge">Capabilities</code>, и всё будет по-старому.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/1642">PR 1642</a>.</p> <p><br /></p> <p><em>Больше капабилитей богу капабилитей!</em></p> <p><br /></p> <h1 id="upd-selenide-6.1.2">UPD Selenide 6.1.2</h1> <p>Мы выпустили Selenide 6.1.2 с обновлением на Selenium 4.1.1 - эта версия содержит несколько заметных исправлений.</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2021/11/24/selenide-6.1.1/ http://ru.selenide.org/2021/11/24/selenide-6.1.1 2021-11-24T00:00:00+00:00 Вышла Selenide 6.1.0 <p><br /></p> <h1 id="tere">TERE!</h1> <p><br /> Мы зарелизили <a href="https://github.com/selenide/selenide/milestone/137?closed=1">Selenide 6.1.0</a>.</p> <p><br /></p> <h1 id="добавили-поддержку-selenideproperties">Добавили поддержку <code class="language-plaintext highlighter-rouge">selenide.properties</code></h1> <p>Теперь Селенид умеет читать настройки из отдельного файлика <code class="language-plaintext highlighter-rouge">selenide.properties</code>, если таковой найдётся в classpath.</p> <p>NB! Лично я всё ещё не вижу пользы от этого, ведь проще задать настройки</p> <ol> <li>прямо в коде: <code class="language-plaintext highlighter-rouge">Configuration.timeout = 8000;</code></li> <li>или через system properties: <code class="language-plaintext highlighter-rouge">-Dselenide.timeout=8000</code>.</li> </ol> <p>Прошу, не надо резко ломиться генерировать эти файлики. Используйте <code class="language-plaintext highlighter-rouge">selenide.properties</code>, только если у вас есть хорошие причины для этого, а не просто потому, что теперь это модно или “так красиво”.</p> <p>Спасибо <a href="https://github.com/petroOv-PDFfiller">Petro Ovcharenko</a> за <a href="https://github.com/selenide/selenide/pull/1601">PR 1601</a>.</p> <p><br /></p> <h1 id="добавили-возможность-тонкой-настройки-прокси">Добавили возможность тонкой настройки прокси</h1> <p>Как вы знаете, Селенид умеет запускать свой прокси-сервер, который даёт нам некоторые дополнительные возможности. Но возможности для настройки прокси до сих пор были ограниченные. Только <code class="language-plaintext highlighter-rouge">Configuration.proxyHost</code> и <code class="language-plaintext highlighter-rouge">Configuration.proxyPort</code>.</p> <p>Теперь же можно будет получить инстанс BrowserModProxy и настроить его как угодно до запуска браузера.</p> <p>NB! Пожалуйста, не переусердствуйте с этим. Тут очень легко выстрелить себе в ногу.</p> <p>И если ваши настройки действительно помогли вам, то возможно, они помогут и другим. Расскажите нам, что вы там такого настроили - может, стоит сделать это в селениде по умолчанию?</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1561">issue 1561</a>. Спасибо <a href="https://github.com/BorisOsipov">Boris Osipov</a> за <a href="https://github.com/selenide/selenide/pull/1620">PR 1620</a>.</p> <p><br /></p> <h1 id="добавили-костыль-для-избежания-случайных-noclassdeffounderror-в-webdriverexception">Добавили костыль для избежания случайных <code class="language-plaintext highlighter-rouge">NoClassDefFoundError</code> в <code class="language-plaintext highlighter-rouge">WebDriverException</code>.</h1> <p>В Селениум есть <a href="https://github.com/SeleniumHQ/selenium/issues/9784">бага</a>, которая полностью до сих пор не исправлена. Но вы её больше не увидите, потому что теперь в селениде есть костыль против неё. :)</p> <p>См. <a href="https://github.com/selenide/selenide/commit/2eff0307e3a">костыль</a>.</p> <p><br /></p> <h1 id="поменяли-тип-параметра-selenideconfigbrowsercapabilities">Поменяли тип параметра <code class="language-plaintext highlighter-rouge">SelenideConfig.browserCapabilities()</code></h1> <p>… с <code class="language-plaintext highlighter-rouge">DesiredCapabilities</code> на <code class="language-plaintext highlighter-rouge">MutableCapabilities</code>.</p> <p>Это позволяет упростить ваш код и не заворачивать <code class="language-plaintext highlighter-rouge">ChromeOptions</code> в <code class="language-plaintext highlighter-rouge">DesiredCapabilities</code>. Больше об упрощении капабилитей этом будет в следующем релизе <code class="language-plaintext highlighter-rouge">Selenide 6.1.1</code>.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/1637">PR 1637</a>.</p> <p><br /></p> <h1 id="обновились-на-selenium-webdriver-410">Обновились на Selenium Webdriver 4.1.0</h1> <p>Спасибо <a href="https://github.com/BorisOsipov">Boris Osipov</a> за <a href="https://github.com/selenide/selenide/pull/1638">PR 1638</a>.</p> <p><br /></p> <h1 id="удалили-метод-shadowroot">Удалили метод <code class="language-plaintext highlighter-rouge">$.shadowRoot()</code></h1> <p>Этот метод сломался после обновления на Chrome 96, и вероятно, вскоре сломается и в остальных браузерах. Починить его муторно, и при этом <a href="https://github.com/selenide/selenide/issues/1515#issuecomment-894476289">пользы от этого метода немного</a>, ведь для поиска элементов внутри Shadow DOM есть <a href="/2020/03/18/selenide-5.10.0/">более удобные и быстрые методы</a>.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1640">issue 1640</a> и <a href="https://github.com/selenide/selenide/pull/1641">PR 1641</a>.</p> <p><br /></p> <h1 id="новости">Новости</h1> <ul> <li>Первый <a href="https://www.eventbrite.com/e/propeller-testops-hackathon-registration-194333114577">TestOps Hackathon</a> от PropellerAds и Qameta Software перенесли на 1-6 декабря. Регистрируйтесь!</li> <li><a href="https://www.lambdatest.com/selenium-automation-testing-with-selenide-framework">Как использовать Selenide с сервисом Lambdatest</a></li> <li>Пост <a href="https://mbbaig.blog/selenide-webdriverfactory/">Selenide - Create a Custom WebDriver</a> от Boris Bay</li> <li>Оказывается, <a href="https://www.linkedin.com/feed/update/urn:li:activity:6867477909766979584/">LinkedIn проводит курсы по Селениду</a> и даже выдаёт красивенькие дипломы.</li> </ul> <p><br /></p> <h1 id="статистика-использования-селенида">Статистика использования Селенида</h1> <center> <img src="/images/2021/11/selenide.downloads.png" width="800" /> </center> <p><br /> В октябре мы сделали мощный скачок и перевалили за <strong>280 тысяч скачиваний</strong> в месяц. Эгегей!</p> <p><em>Больше скачиваний богу скачиваний!</em></p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2021/11/23/selenide-6.1.0/ http://ru.selenide.org/2021/11/23/selenide-6.1.0 2021-11-23T00:00:00+00:00 Вышла Selenide 6.0.1 <p><br /></p> <h1 id="день-рождения">День рождения!</h1> <p>Ура! Сложно поверить, но сегодня Селениду исполняется… 10 лет!<br /> Именно в этот день 10 лет назад был сделан <a href="https://github.com/selenide/selenide/commit/3716078fc7fda8c5da01d871882d513cbd97cd0e">первый коммит</a> в репозитории.</p> <p>Огромное спасибо всем, кто участвовал в проекте, коммитил, репортил баги, предлагал идеи, отвечал на вопросы в форумах, критиковал и рассказывал про селенид на конференциях и митапах. Да и просто решился использовать селенид в своих проектах. Вы все - часть этого движения.</p> <p><br /> Ну а мы в честь юбилея зарелизили мажорную версию <a href="https://github.com/selenide/selenide/milestone/136?closed=1">Selenide 6.0.1</a>.</p> <p><br /></p> <h1 id="обновились-на-selenium-webdriver-400">Обновились на Selenium Webdriver 4.0.0</h1> <p>Если вы не используете Grid, то для вас особо ничего и не должно поменяться. Всё более-менее работает как раньше. Ну там, переименовали или задеприкейтили некоторые классы, вроде нестрашно.</p> <p>В Selenium 4 появились и <a href="https://www.browserstack.com/guide/selenium-4-features">новые возможности</a> (такие как CDP и Relative locators), но какой-то отдельной поддержки для них в селениде мы пока не делали. Если понадобится, будем делать в следующих версиях.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1162">issue 1162</a>, <a href="https://github.com/selenide/selenide/pull/1605">PR 1605</a>, <a href="https://github.com/selenide/selenide/pull/1614">PR 1614</a> и <a href="https://github.com/selenide/selenide/pull/1617">PR 1617</a>.</p> <p><br /></p> <h1 id="разбили-selenide-на-несколько-артефактов">Разбили Selenide на несколько артефактов</h1> <p>Раньше весь код селенида поставлялся одним джарником: <code class="language-plaintext highlighter-rouge">selenide-5.25.0.jar</code>.<br /> Предполагалось, что дополнительно к нему вы должны были сами добавить и другие зависимости: JUnit или TestNG, и возможно, BrowserMobProxy.</p> <p>Теперь же мы решили упростить вам задачу (особенно с прокси).</p> <ol> <li>Для пользователей Selenide и JUnit5 ничего не меняется: <br /><code class="language-plaintext highlighter-rouge">testImplementation("com.codeborne:selenide:6.0.1)</code></li> <li>Пользователи JUnit4 должны будут использовать <br /> <code class="language-plaintext highlighter-rouge">testImplementation("com.codeborne:selenide-junit4:6.0.1)</code></li> <li>Пользователи TestNG должны будут использовать <br /> <code class="language-plaintext highlighter-rouge">testImplementation("com.codeborne:selenide-testng:6.0.1)</code></li> <li>Если вы хотите использовать прокси, достаточно добавить в проект зависимость <br /> <code class="language-plaintext highlighter-rouge">testImplementation("com.codeborne:selenide-proxy:6.0.1)</code> - и можно больше не заморачиваться с версиями BrowserUpProxy, Netty и т.п.</li> <li>Ну и если среди вас есть радикальные ненавистники статических методов, теперь и вы сможете быть счастливы, используя <br /> <code class="language-plaintext highlighter-rouge">testImplementation("com.codeborne:selenide-core:6.0.1)</code> - и тогда у вас в проекте не будет статических методов <code class="language-plaintext highlighter-rouge">Selenide.*</code>, а только чистый <code class="language-plaintext highlighter-rouge">SelenideDriver</code>.</li> </ol> <p>См. <a href="https://github.com/selenide/selenide/pull/1612">PR 1612</a>.</p> <p><br /></p> <h1 id="подчистили-кучу-deprecated-методов">Подчистили кучу deprecated методов</h1> <p>По <a href="https://github.com/selenide/selenide/pull/1607/files">этой ссылке</a> всегда можете найти, что именно удалили и чем это заменить.<br /> В частности,</p> <ul> <li><code class="language-plaintext highlighter-rouge">ElementsCollection.shouldHaveSize()</code> -&gt; <code class="language-plaintext highlighter-rouge">ElementsCollection.shouldHave(size())</code></li> <li><code class="language-plaintext highlighter-rouge">$.waitUntil(_, timeout)</code> -&gt; <code class="language-plaintext highlighter-rouge">$.should(_, Duration.ofMillis(timeout))</code></li> <li><code class="language-plaintext highlighter-rouge">$.waitWhile(_, timeout)</code> -&gt; <code class="language-plaintext highlighter-rouge">$.shouldNot(_, Duration.ofMillis(timeout))</code></li> <li><code class="language-plaintext highlighter-rouge">Condition.disappears</code> -&gt; <code class="language-plaintext highlighter-rouge">Condition.hidden</code></li> <li><code class="language-plaintext highlighter-rouge">Condition.matchesText</code> -&gt; <code class="language-plaintext highlighter-rouge">Condition.matchText</code></li> <li><code class="language-plaintext highlighter-rouge">Selenide.close</code> -&gt; <code class="language-plaintext highlighter-rouge">Selenide.closeWebDriver()</code> или <code class="language-plaintext highlighter-rouge">Selenide.closeWindow()</code> <br /></li> </ul> <p>Спасибо <a href="https://github.com/BorisOsipov">Boris Osipov</a> за <a href="https://github.com/selenide/selenide/pull/1607/files">PR 1607</a> и <a href="https://github.com/selenide/selenide/pull/1609">PR 1609</a>.</p> <p><br /></p> <h1 id="удалили-поддержку-браузера-legacy_firefox">Удалили поддержку браузера “legacy_firefox”</h1> <p>Это был такой старый вебдрайвер, который работал только с Firefox 52 и старше. Полагаю, ему пора на покой.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/1610">PR 1610</a>.</p> <p><br /></p> <h1 id="удалили-старые-настройки">Удалили старые настройки</h1> <h3 id="configurationstartmaximized"><code class="language-plaintext highlighter-rouge">Configuration.startMaximized</code></h3> <p>Есть мнение, что это плохая практика, потому что размер окна браузера зависит от текущего окружения, что может привести к моргающим тестам. Рекомендуем использовать <code class="language-plaintext highlighter-rouge">Configuration.browserSize</code> (по умолчанию <code class="language-plaintext highlighter-rouge">1366x768</code>).</p> <h3 id="configurationversatilesetvalue"><code class="language-plaintext highlighter-rouge">Configuration.versatileSetValue</code></h3> <p>Скорее всего вы её и не использовали, ведь она давным-давно была <code class="language-plaintext highlighter-rouge">false</code> по умолчанию.<br /> Для выбора значений в <code class="language-plaintext highlighter-rouge">&lt;select&gt;</code> и <code class="language-plaintext highlighter-rouge">&lt;input type=radio&gt;</code> можно использовать старый добрые методы <code class="language-plaintext highlighter-rouge">$.selectOptionByValue()</code> и <code class="language-plaintext highlighter-rouge">$.selectRadio()</code>.</p> <p>Спасибо <a href="https://github.com/BorisOsipov">Boris Osipov</a> за <a href="https://github.com/selenide/selenide/pull/1619">PR 1619</a>.</p> <p><br /></p> <h1 id="починили-метод-selenidesleepn">Починили метод <code class="language-plaintext highlighter-rouge">Selenide.sleep(N)</code></h1> <p>Казалось бы, разве такой просто однострочный метод может быть сломан? А вот может. Оказывается, стандартный джавовый метод <code class="language-plaintext highlighter-rouge">Thread.sleep(N)</code> не обязательно спит именно N мс, он может проснуться и раньше. И это может привести к моргающим тестам, если ваш тест рассчитывал именно на определённую паузу. Век живи - век учись.</p> <p>Теперь метод <code class="language-plaintext highlighter-rouge">Selenide.sleep(N)</code> гарантированно спит заданное количество миллисекунд.</p> <p>См. <a href="https://github.com/selenide/selenide/blob/b05d53dfb794ee02e795587867c6ec8022171040/statics/src/main/java/com/codeborne/selenide/Selenide.java#L258">реализацию</a>.</p> <p><br /></p> <h1 id="добавили-метод-для-добавления-и-удаления-webdriverlistener">Добавили метод для добавления и удаления <code class="language-plaintext highlighter-rouge">WebDriverListener</code></h1> <p>Раньше в селениде можно было добавлять <code class="language-plaintext highlighter-rouge">WebDriverEventListener</code>, но этот класс был заменён на <code class="language-plaintext highlighter-rouge">WebDriverListener</code> в Selenium 4. Ну вот, пришлось поддерживать оба.</p> <p><br /></p> <p>См. <a href="https://github.com/selenide/selenide/issues/1615">issue 1615</a> и <a href="https://github.com/selenide/selenide/pull/1616">PR 1616</a>.</p> <p><br /></p> <h1 id="поменяли-сигнатуру-метода-conditionapply">Поменяли сигнатуру метода <code class="language-plaintext highlighter-rouge">Condition.apply</code></h1> <p>Если вы не писали свои Conditions, то вас это не касается.</p> <p>А если успели наваять, то придётся их немножко дополнить.</p> <p>Итак, раньше в классе <code class="language-plaintext highlighter-rouge">Condition</code> был метод <code class="language-plaintext highlighter-rouge">apply</code>, который возвращал boolean:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">apply</span><span class="o">(</span><span class="nc">Driver</span> <span class="n">driver</span><span class="o">,</span> <span class="nc">WebElement</span> <span class="n">element</span><span class="o">)</span> </code></pre></div></div> <p>Теперь его нужно переименовать в <code class="language-plaintext highlighter-rouge">check</code>, и возвращать он должен не просто boolean, а <code class="language-plaintext highlighter-rouge">CheckResult</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="nc">CheckResult</span> <span class="nf">check</span><span class="o">(</span><span class="nc">Driver</span> <span class="n">driver</span><span class="o">,</span> <span class="nc">WebElement</span> <span class="n">element</span><span class="o">)</span> </code></pre></div></div> <p>А этот <code class="language-plaintext highlighter-rouge">CheckResult</code> содержит не только признак “проверка прошла / не прошла”, но и какое значение было у элемента в тот момент. Это позволить формировать более точное сообщение об ошибке в случае падения теста.</p> <p>P.S. Впрочем, старый метод <code class="language-plaintext highlighter-rouge">apply</code> всё ещё остался как deprecated, поэтому какое-то время вы можете сидеть на старых кондишинах. Просто при падении теста строчка “Actual value: “ не будет добавляться к сообщению об ошибке. Но это и не всегда критично.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/217">issue 217</a>, <a href="https://github.com/selenide/selenide/pull/1586">PR 1586</a> и <a href="https://github.com/selenide/selenide/pull/1618">PR 1618</a>.</p> <p><br /></p> <h1 id="selenide-selenoid-201">selenide-selenoid 2.0.1</h1> <p>Мы выпустили <a href="https://github.com/selenide/selenide-selenoid/releases/tag/v2.0.0"><code class="language-plaintext highlighter-rouge">selenide-selenoid:2.0.0</code></a> с обновлением на Selenide 6.0.1</p> <p><br /></p> <h1 id="selenide-appium">selenide-appium</h1> <p>Кажется, пока что Appium не поддерживает Selenium 4, так что <code class="language-plaintext highlighter-rouge">selenide-appium</code> пока обновить не можем. Будет следить за ситуацией.</p> <p><br /></p> <h1 id="upd-selenide-602">UPD Selenide 6.0.2</h1> <p>Обнаружилась проблемка с проектами на TestNG, по-быстрому выпустили хотфикс 6.0.2.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1623">issue 1623</a></p> <p><br /></p> <h1 id="upd-selenide-603">UPD Selenide 6.0.3</h1> <p>Оказалось, что Maven может подтягивать старый <code class="language-plaintext highlighter-rouge">selenium-api-3*.jar</code>, если он найден в дереве зависимостей (обычно у BrowserUpProxy или Allure).</p> <p>Мне давно кажется, что тут Maven мог бы быть чуточку поумнее и выбирать всё-таки более свежую версию.<br /> Но поскольку люди довольно часто наступают на эти грабли, мы решили запилить костыль в селениде.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/1625">костыль 1625</a></p> <p><br /></p> <h1 id="что-почитать-про-selenium-4">Что почитать про Selenium 4</h1> <ul> <li><a href="https://applitools.com/blog/selenium-4/">What’s New In Selenium 4?</a> by Applitools</li> <li><a href="https://www.browserstack.com/guide/selenium-4-features">Selenium 4: Understanding Key Features</a> by BrowserStack</li> <li><a href="https://saucelabs.com/selenium-4">A comprehensive guide to Selenium 4</a> by SauceLabs</li> <li><a href="https://www.lambdatest.com/blog/what-is-deprecated-in-selenium4/">What Is New In Selenium 4 And What Is Deprecated In It?</a> by LambdaTest</li> <li><a href="https://www.selenium.dev/documentation/">Обновлённый сайт Selenium</a></li> </ul> <p><br /></p> <h1 id="другие-новости">Другие новости</h1> <ul> <li>внезапный <a href="https://youtu.be/mK-6-k5EwQM">выпуск Heisenbug Show</a>, посвящённый 10-летию Селенида.</li> <li>Первый <a href="https://www.eventbrite.com/e/propeller-testops-hackathon-registration-194333114577">TestOps Hackathon</a> от PropellerAds и Qameta Software - с 12 по 16 ноября. Регистрируйтесь!</li> <li>Ребята из Aerokube выпустили <a href="https://github.com/aerokube/lightning-java">альтернативный клиент WebDriver</a>. Теоретически теперь селенид может работать на нём вместо Selenium Webdriver. Звучит заманчиво?</li> <li><a href="https://www.youtube.com/watch?v=ch5sxsQJzW4">Koncerns: Почему я не тороплюсь на Котлин</a></li> <li>Я пока не разбирался, но люди вроде хвалят: <a href="https://github.com/markhobson/docker-maven-chrome">какие-то образы Docker для Selenium</a></li> </ul> <p><br /></p> <h1 id="статистика-использования-селенида">Статистика использования Селенида</h1> <center> <img src="/images/2021/10/selenide.downloads.png" width="800" /> </center> <p><br /> Перевалили за <strong>255 тысяч скачиваний</strong> в месяц.</p> <p>Что нас ждёт впереди?</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2021/10/25/selenide-6.0.1/ http://ru.selenide.org/2021/10/25/selenide-6.0.1 2021-10-25T00:00:00+00:00 Вышла Selenide 5.25.0 <p>Добрый вечер!</p> <p>Мы зарелизили <a href="https://github.com/selenide/selenide/milestone/131?closed=1">Selenide 5.25.0</a>.</p> <blockquote> <p><strong>Очень советую обновиться</strong>,<br /> потому что за этим релизом грядут ещё большие изменения, включая полноценный релиз Selenium 4.<br /> Если не обновитесь сейчас, потом будет намного сложнее разгребать завалы!</p> </blockquote> <p>Это прямо большой релиз с кучей изменений, так что запаситесь попкорном и заварите чаю. Погнали!</p> <ul> <li><a href="#support-webdriver-4.0.0.RC1">Поддержка Selenium Webdriver 4.0.0 RC1</a></li> <li><a href="#opentest4j">Добавили поддержку OpenTest4j</a></li> <li><a href="#stacktrace-in-soft-asserts">Показываем стектрейс под каждой ошибкой в SoftAsserts</a></li> <li><a href="#get-shadow-root">Добавили метод <code class="language-plaintext highlighter-rouge">$.shadowRoot()</code></a></li> <li><a href="#get-ancestor">Добавили метод <code class="language-plaintext highlighter-rouge">$.ancestor()</code></a></li> <li><a href="#enrich-ancestor">Обогатили методы <code class="language-plaintext highlighter-rouge">$.closest()</code> и <code class="language-plaintext highlighter-rouge">$.ancestor()</code></a></li> <li><a href="#fixed-element-screenshot">Починили метод <code class="language-plaintext highlighter-rouge">$.screenshot()</code> на маках</a></li> <li><a href="#actual-value-at-the-moment-of-last-check">При падении текстовых проверок селенид выдаёт точное значение на момент падения</a></li> <li><a href="#empty-text-not-allowed">Запретили пустой аргумент в методе <code class="language-plaintext highlighter-rouge">$.matchText("")</code></a></li> <li><a href="#check-webdriver-title">Добавили проверку <code class="language-plaintext highlighter-rouge">webdriver().shouldHave(title(...))</code></a></li> <li><a href="#release-selenide-selenoid-1.2.0">selenide-selenoid 1.2.0</a></li> <li><a href="#release-selenide-appium-1.7.0">selenide-appium 1.7.0</a></li> <li><a href="#news">Ссылки</a></li> <li><a href="#statistics">Статистика использования Селенида</a></li> <li><a href="#selenide-anniversary">Юбилей Selenide</a></li> </ul> <p><br /></p> <h1 id="support-webdriver-4.0.0.RC1">Поддержка Selenium Webdriver 4.0.0 RC1</h1> <p>Мы выпустили две сборки Selenide 5.25.0: обычную и хипстерскую.<br /> Можете сами выбрать:</p> <table> <tbody> <tr> <td>либо</td> <td><code class="language-plaintext highlighter-rouge">com.codeborne:selenide:5.25.0</code></td> <td>(с <code class="language-plaintext highlighter-rouge">Selenium 3.x</code>),</td> </tr> <tr> <td>либо</td> <td><code class="language-plaintext highlighter-rouge">com.codeborne:selenide:5.25.0-selenium-4.0.0-rc-1</code></td> <td>(с <code class="language-plaintext highlighter-rouge">Selenium 4.0.0 RC1</code>).</td> </tr> </tbody> </table> <p><br /></p> <h1 id="opentest4j">Добавили поддержку OpenTest4j</h1> <p>Если вы ещё не слышали, <a href="https://github.com/ota4j-team/opentest4j">OpenTest4j</a> - это маленькая библиотека для assertion errors, созданная по инициативе ребят из JUnit 5. Идея в том, чтобы все тестовые фреймворки кидали именно эти ошибки, а все IDE их поддерживали. Её уже давно поддерживают крупные игроки типа JUnit, TestNG, AssertJ, IDEA и Eclipse, а вот теперь ещё и Selenide.</p> <p><strong>Что изменится лично для вас:</strong><br /> Когда ваш UI тест падает (ну, <a href="https://github.com/selenide/selenide/issues/1589">почти всегда</a>), IDEA теперь красивенько показывает внизу ссылочку <code class="language-plaintext highlighter-rouge">&lt;Click to see difference&gt;</code>. Вы можете её кликнуть и увидеть красивый идеевский DIFF в отдельном диалоге. Очень удобно при отладке.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/969">issue 969</a> и <a href="https://github.com/selenide/selenide/pull/1545">PR 1545</a>.</p> <p>NB! Если вы в своих проектах использовать напрямую селенидовские классы ошибок (наследовали или кидали), то придётся чуть подпилить код, потому что мы чутка изменили сигнатуры их конструкторов:</p> <ul> <li>поменяли местами аргументы “expected” и “actual”</li> <li>убрали ненужный параметр “driver” из большинства конструкторов</li> </ul> <p><br /></p> <center> <img src="/images/2021/09/idea-see-diff.png" width="400" style="margin-right: 20px;" /> <img src="/images/2021/09/idea-diff.png" width="300" /> </center> <p><br /></p> <h1 id="stacktrace-in-soft-asserts">Показываем стектрейс под каждой ошибкой в SoftAsserts</h1> <p>До сих пор селенидовские софт ассерты показывали только один общий стектрейс после всех ошибок. А удобнее видеть стектрейс под каждой, тогда легко кликнуть на нужную строчку и попасть сразу в нужное место в коде.</p> <p>Теперь стектрейс будет под каждой ошибкой. Правда, теперь общее сообщение об ошибке стало гораздо длиннее, но ведь их не должно быть часто и много, правда? ;)</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1543">issue 1543</a> и <a href="https://github.com/selenide/selenide/pull/1545">PR 1545</a></p> <p><br /></p> <h1 id="get-shadow-root">Добавили метод <code class="language-plaintext highlighter-rouge">$.shadowRoot()</code></h1> <p>Раньше можно было только искать элементы внутри shadow root, а теперь можно получить и сам shadow root. Правда, пользы от этого пока немного, т.к. поиск внутри этого элемента не поддерживается (браузерами или вебдрайверами, я уж не знаю - запутался).</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1515">issue 1515</a> и <a href="https://github.com/selenide/selenide/pull/1517">PR 1517</a>.</p> <p><br /></p> <h1 id="get-ancestor">Добавили метод <code class="language-plaintext highlighter-rouge">$.ancestor()</code></h1> <p>По сути это просто синоним к существующему методу <code class="language-plaintext highlighter-rouge">$.closest()</code>. Но только название <code class="language-plaintext highlighter-rouge">closest</code> было родом из JQuery (олды помнят!), а <code class="language-plaintext highlighter-rouge">ancestor</code> должно быть более понятным, т.к. это общеизвестный термин из XPath.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1556">issue 1556</a>.<br /> Спасибо <a href="https://github.com/bereg2k">Oleg Berezhnoy</a> за <a href="https://github.com/selenide/selenide/pull/1567">PR 1567</a></p> <p><br /></p> <h1 id="enrich-ancestor">Обогатили методы <code class="language-plaintext highlighter-rouge">$.closest()</code> и <code class="language-plaintext highlighter-rouge">$.ancestor()</code></h1> <p>Раньше этот метод умел искать элемент только по тэгу или классу:</p> <ul> <li><code class="language-plaintext highlighter-rouge">$.ancestor("table").shouldBe(visible)</code></li> <li><code class="language-plaintext highlighter-rouge">$.ancestor(".form").shouldBe(visible)</code></li> </ul> <p>То теперь добавился поиск по атрибуту:</p> <ul> <li><code class="language-plaintext highlighter-rouge">$.ancestor("[argument-name]");</code></li> <li><code class="language-plaintext highlighter-rouge">$.ancestor("[argument-name=argument-value]");</code></li> </ul> <p>Спасибо <a href="https://github.com/plagov">Vitali Plagov</a> за <a href="https://github.com/selenide/selenide/pull/1554">PR 1554</a></p> <p><br /></p> <h1 id="fixed-element-screenshot">Починили метод <code class="language-plaintext highlighter-rouge">$.screenshot()</code> на маках</h1> <p>В селениде уже давно есть метод <code class="language-plaintext highlighter-rouge">$.screenshot()</code>, который позволяет сделать снимок не всего экрана, а только указанного элемента. Оказалось, что этот метод неправильно работал на MacBook: вырезал не ту область экрана (из-за всей этой чехарды с пикселями на дисплее Retina).</p> <p>К счастью, мы обнаружили, что соответствующий функционал уже давно реализован в селениуме, поэтому мы вырезали костыльный код из селенида и использовали стандартный метод вебдрайвера. Работает как минимум на Chrome, Firefox, Edge.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1571">issue 1571</a> и <a href="https://github.com/selenide/selenide/pull/1576">PR 1576</a>.</p> <p><br /></p> <h1 id="actual-value-at-the-moment-of-last-check">При падении текстовых проверок селенид выдаёт точное значение на момент падения</h1> <p>Ничего себе, какие старые болячки мы иногда чиним! Этот тикет был зарегистрирован аж <em>6 сентября 2015</em>!</p> <p><strong>В общем, история такая.</strong></p> <p>Допустим, в вашем тесте есть проверка</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Hello"</span><span class="o">));</span> </code></pre></div></div> <p>И стандартный таймаут в 4 секунды. И вот:</p> <ol> <li>в течение 4 секунд селенид проверяет-проверяет текст, а он всё не тот и не тот (допустим, “Goodbye”).</li> <li>таймаут истекает,</li> <li>селенид решает кинуть ошибку,</li> <li>начинает составлять сообщение и добавляет к нему текущий текст элемента - а он как раз в этот момент взял и да поменялся! Допустим, на “Hello”.</li> </ol> <p>Такое случается очень редко, но когда случается, может вызвать недопонимание. Вы видите ошибку:</p> <blockquote> <p>Текст не совпал. Ожидался: Hello, а был: Hello.</p> </blockquote> <p>и чувствуете, как мозг начинает подгорать…</p> <p>Теперь Селенид запоминает <strong>именно тот текст</strong>, который был на момент проверки, и именно его добавляет в сообщение об ошибке. Да здравствуют неподгоревшие мозги!</p> <p>P.S. В будущем мы планируем этот механизм ещё больше усовершенствовать, и выводить всю историю изменений текста в течение этих несчастных 4 секунд. Больше отчётов богу отчётов!</p> <p>См. <a href="https://github.com/selenide/selenide/issues/217">issue 217</a> и <a href="https://github.com/selenide/selenide/pull/1566">PR 1566</a>.<br /> Спасибо <a href="https://github.com/fokinp">Pavel Fokin</a> за <a href="https://github.com/selenide/selenide/pull/1313">PR 1313</a>.</p> <p><br /></p> <h1 id="empty-text-not-allowed">Запретили пустой аргумент в методе <code class="language-plaintext highlighter-rouge">$.matchText("")</code></h1> <p>В селениде есть метод для проверки текста элемента регулярным выражением:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#child_div1"</span><span class="o">).</span><span class="na">should</span><span class="o">(</span><span class="n">matchText</span><span class="o">(</span><span class="s">"Таллин{1,2}"</span><span class="o">)));</span> </code></pre></div></div> <p>И тут мы обнаружили, что метод <code class="language-plaintext highlighter-rouge">matchText</code> позволяет передать ему пустую строку, что можем привести к ложно-зелёным тестам. Теперь же при попытке вызвать <code class="language-plaintext highlighter-rouge">$.should(matchText("")))</code> вы сразу увидите такую ошибку:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">IllegalArgumentException</span><span class="o">:</span> <span class="nc">Argument</span> <span class="n">must</span> <span class="n">not</span> <span class="n">be</span> <span class="kc">null</span> <span class="n">or</span> <span class="n">empty</span> <span class="n">string</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/pull/1566/commits/3f6421226c">PR 1566</a></p> <p><br /></p> <h1 id="check-webdriver-title">Добавили проверку <code class="language-plaintext highlighter-rouge">webdriver().shouldHave(title(...))</code></h1> <p>Как обычно, есть варианты со стандартным таймаутом и кастомным:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">webdriver</span><span class="o">().</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">title</span><span class="o">(</span><span class="s">"Login page"</span><span class="o">));</span> <span class="n">webdriver</span><span class="o">().</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">title</span><span class="o">(</span><span class="s">"Login page"</span><span class="o">),</span> <span class="n">ofMillis</span><span class="o">(</span><span class="mi">10</span><span class="o">));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1573">issue 1573</a>.<br /> Спасибо <a href="https://github.com/ervuks">Ervīns Patmalnieks</a> за <a href="https://github.com/selenide/selenide/pull/1579">PR 1579</a>.</p> <p><br /></p> <h1 id="release-selenide-selenoid-1.2.0">selenide-selenoid 1.2.0</h1> <p>Мы выпустили <a href="https://github.com/selenide/selenide-selenoid/releases/tag/v1.2.0"><code class="language-plaintext highlighter-rouge">selenide-selenoid:1.2.0</code></a> с обновлением на Selenide 5.25.0</p> <p><br /></p> <h1 id="release-selenide-appium-1.7.0">selenide-appium 1.7.0</h1> <p>Мы выпустили <a href="https://github.com/selenide/selenide-appium/releases/tag/v1.7.0"><code class="language-plaintext highlighter-rouge">selenide-appium:1.7.0</code></a> с обновлением на Selenide 5.25.0</p> <p><br /> <br /></p> <h1 id="news">Ссылки</h1> <ul> <li>Вышло моё <a href="https://www.youtube.com/watch?v=o_jAKaVzjyc">интервью с Лёшей Маршалом</a> на ютуб канале “Тестирование ПО”</li> <li>5-7 октября снова будет Гейзенбаг - <a href="https://heisenbug-moscow.ru/schedule/">советую!</a></li> <li><a href="https://youtube.com/playlist?list=PLsVTVVvrKX9td9Zm_4nF6Ywlz6gC5_e7K">Доклады с весеннего Гейзенбага</a> <ul> <li>В т.ч. мой доклад <a href="https://www.youtube.com/watch?v=LDjDtR6kd2c">Flaky tests. Метод</a></li> <li>В т.ч. мой мастер-класс <a href="https://heisenbug-piter.ru/2021/spb/talks/3tg2q9jq8nvldssitjuzvr/">Как начать проект автоматизации. Продолжение.</a> - <a href="https://www.youtube.com/watch?v=h254Tccxgq4&amp;list=PLsVTVVvrKX9td9Zm_4nF6Ywlz6gC5_e7K&amp;index=15&amp;ab_channel=Heisenbug">часть 1</a>, <a href="https://www.youtube.com/watch?v=WETyt87o_R4&amp;list=PLsVTVVvrKX9td9Zm_4nF6Ywlz6gC5_e7K&amp;index=16&amp;t=3s&amp;ab_channel=Heisenbug">часть 2</a>.</li> </ul> </li> <li>Лекция <a href="https://www.youtube.com/watch?v=xknQcm6H87M">Автоматизация для QA: Selenide</a></li> <li>Пост <a href="https://www.indellient.com/blog/automated-testing-using-selenide-testng/">Using Selenide &amp; TestNG</a></li> </ul> <p><br /></p> <h1 id="statistics">Статистика использования Селенида</h1> <center> <img src="/images/2021/09/selenide.downloads.png" width="800" /> </center> <p><br /> Знаковый рубеж пройден: перевалили за <strong>250 тысяч скачиваний</strong> в месяц.</p> <p><br /></p> <h2 id="selenide-anniversary">Юбилей Selenide</h2> <p>Кстати, мы вплотную подошли к ещё одному знаковому рубежу: в октябре Селениду исполняется… 10 лет!<br /> В это сложно поверить, но <a href="https://github.com/selenide/selenide/commit/3716078fc7fda8c5da01d871882d513cbd97cd0e">первый коммит</a> в репозитории был сделан аж 25 октября 2011 года. Вы только посмотрите, какой он был нелепый! :)</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2021/09/28/selenide-5.25.0/ http://ru.selenide.org/2021/09/28/selenide-5.25.0 2021-09-28T00:00:00+00:00 Вышла Selenide 5.24.0 <p>Добрый вечер!</p> <p>29 августа 1997 года компьютерная система Скайнет вышла из-под контроля и нанесла ядерный удар по России. Так началась война между терминаторами и человечеством.</p> <p>С тех прошло 24 года, с ума сойти! Мы живём в будущем! И пока ещё мы управляем компьютерами.</p> <p>Я каждый год отмечаю этот день, и сегодня в честь праздника мы зарелизили <a href="https://github.com/selenide/selenide/milestone/130?closed=1">Selenide 5.24.0</a>.</p> <p><br /></p> <h1 id="добавили-метод-executecommand-duration">Добавили метод <code class="language-plaintext highlighter-rouge">$.execute(Command, Duration)</code></h1> <p>для запуска самопальных команд с заданным таймаутом.</p> <p>В <a href="https://ru.selenide.org/2019/09/02/selenide-5.3.0/">Selenide 5.3.0</a> мы добавили возможность легко запускать самопальные команды с помощью метода <code class="language-plaintext highlighter-rouge">$.execute()</code>. Но тогда не было возможности задать кастомный таймаут. Теперь можно.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1525">issue 1525</a>.<br /> Спасибо <a href="https://github.com/evpl">Evgenii Plugatar</a> за <a href="https://github.com/selenide/selenide/pull/1531">PR 1531</a></p> <p><br /></p> <h1 id="методы-executecommand-и-executecommand-duration-больше-не-передают-параметры-заданной-команде">Методы <code class="language-plaintext highlighter-rouge">$.execute(Command)</code> и <code class="language-plaintext highlighter-rouge">$.execute(Command, Duration)</code> больше не передают параметры заданной команде</h1> <p>Это мелочь, но теоретически может сломать ваши самопальные команды, если они у вас есть. Будьте начеку.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1527">issue 1527</a>.<br /> Спасибо <a href="https://github.com/evpl">Evgenii Plugatar</a> за <a href="https://github.com/selenide/selenide/pull/1535">PR 1535</a></p> <p><br /></p> <h1 id="исправили-условия-or-и-and-при-работе-с-несуществующими-элементами">Исправили условия <code class="language-plaintext highlighter-rouge">Or</code> и <code class="language-plaintext highlighter-rouge">And</code> при работе с несуществующими элементами</h1> <p>См. <a href="https://github.com/selenide/selenide/issues/1534">issue 1534</a>.<br /> Спасибо <a href="https://github.com/evpl">Evgenii Plugatar</a> за <a href="https://github.com/selenide/selenide/pull/1539">PR 1539</a></p> <p><br /></p> <h1 id="теперь-условия-or-и-and-не-позволяют-передать-пустой-список-условий">Теперь условия <code class="language-plaintext highlighter-rouge">Or</code> и <code class="language-plaintext highlighter-rouge">And</code> не позволяют передать пустой список условий</h1> <p>Надеюсь, вы и не пытались, потому что это лишено смысла. Но если раньше Селенид это позволял и тесты могли быть ложно зелёными, то теперь вы словите ошибку в рантайме. <br /> Спасибо <a href="https://github.com/evpl">Evgenii Plugatar</a> за <a href="https://github.com/selenide/selenide/pull/1542">PR 1542</a></p> <p><br /></p> <h1 id="переименовали-методы-conditionapplynull-и-collectionconditionapplynull">Переименовали методы <code class="language-plaintext highlighter-rouge">Condition.applyNull()</code> и <code class="language-plaintext highlighter-rouge">CollectionCondition.applyNull()</code></h1> <p>Когда-то по молодости я назвал этот метод <code class="language-plaintext highlighter-rouge">applyNull</code>, но это название вводит в заблуждение. Этот метод говорит о том, выполняется ли условие, если искомый элемент вообще не найден, и теперь он называется <code class="language-plaintext highlighter-rouge">missingElementSatisfiesCondition()</code> - длинновато, зато точно.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1541">issue 1541</a>.<br /> Спасибо <a href="https://github.com/evpl">Evgenii Plugatar</a> за <a href="https://github.com/selenide/selenide/pull/1544">PR 1544</a></p> <p><br /></p> <h1 id="убрали-из-логов-длинные-бесполезные-стектрейсы-при-закрытии-вебдрайвера">Убрали из логов длинные бесполезные стектрейсы при закрытии вебдрайвера</h1> <p>Как вы знаете, Селенид сам закрывает вебдрайвер в тот момент, когда он больше не нужен.<br /> Для этого Селенид запускает всякие хитрые потоки, которые в фоновом режиме следят со состоянием всех открытых вебдрайверов.<br /> И когда наступает момент, закрывают ненужные.</p> <p>Но так бывает, что к моменту закрытия вебдрайвера его уже успел закрыть какой-то другой поток. И тогда Селенид мог плеваться в лог длинными страшными стектрейсами. Это не опасно, но никто ведь не любит спам.</p> <p>В общем, теперь Селенид немного сократил объём спама. :)</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1467">issue 1467</a> и <a href="https://github.com/selenide/selenide/pull/1540">PR 1540</a></p> <p><br /></p> <h1 id="исправили-поиск-shadow-root-внутри-веб-элементов">Исправили поиск shadow root внутри веб-элементов</h1> <p>См. <a href="https://github.com/selenide/selenide/issues/1532">issue 1532</a> и <a href="https://github.com/selenide/selenide/pull/1536">PR 1536</a></p> <p><br /></p> <h1 id="selenide-selenoid-115">selenide-selenoid 1.1.5</h1> <p>Мы выпустили <a href="https://github.com/selenide/selenide-selenoid/releases/tag/v1.1.5"><code class="language-plaintext highlighter-rouge">selenide-selenoid:1.1.5</code></a> с обновлением на Selenide 5.24.0</p> <p><br /></p> <h1 id="selenide-appium-168">selenide-appium 1.6.8</h1> <p>Мы выпустили <a href="https://github.com/selenide/selenide-appium/releases/tag/v1.6.8"><code class="language-plaintext highlighter-rouge">selenide-appium:1.6.8</code></a> с обновлением на Selenide 5.24.0</p> <p><br /> <br /></p> <h1 id="upd-selenide-5241">UPD: Selenide 5.24.1</h1> <p>WebDriverManager - это библиотека (которую Селенид использует под капотом) для скачивания бинарников вебдрайвера. Недавно они выпустили большое обновление 5.0.0 с кучей новых фич. Возможно, мы захотим использовать какие-то из этих фич в Селениде, но пока что мы по-быстрому выпустили <strong>Selenide 5.24.1</strong> с обновлением на WebDriverManager 5.0.1.</p> <p>Спасибо <a href="https://github.com/anilreddy">Anil Kumar Reddy Gaddam</a> за <a href="https://github.com/selenide/selenide/pull/1547">PR 1531</a>.</p> <p><br /></p> <h1 id="upd-selenide-5242">UPD: Selenide 5.24.2</h1> <p>Оказалось, что зависимость <code class="language-plaintext highlighter-rouge">commons-lang3</code> (которую Селенид используем под капотом) больше прилетает транзитивно из WDM 5.x. А раньше прилетала из WDM 4.x. Поэтому нам пришлось по-быстрому добавить явную зависимость <code class="language-plaintext highlighter-rouge">commons-lang3</code> и зарелизить <strong>Selenide 5.24.2</strong>.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1551">issue 1551</a>.</p> <p><br /></p> <h1 id="upd-selenide-5243">UPD: Selenide 5.24.3</h1> <p>Обновились на WebDriverManager 5.0.2, теперь смогли исключить <code class="language-plaintext highlighter-rouge">docker-java</code> и некоторые другие лишние зависимости.</p> <p><br /></p> <h1 id="upd-selenide-5244">UPD: Selenide 5.24.4</h1> <p>Обновились на WebDriverManager 5.0.3, в котором вышел срочный фикс для нового Firefox 92.0 на маке. И кое-что ещё по мелочам.</p> <p><br /> <br /></p> <h1 id="ссылки">Ссылки</h1> <ul> <li>Новое шоу <a href="https://www.youtube.com/channel/UCHmuu4tJjx54fOWzoIVqmaA">Айтишники</a> от Артёма и Севы</li> <li>Оказывается, на Селениде можно писать тесты не только для веб и мобилок, но и для Swing приложений! Вот <a href="https://github.com/framebassman/fest-selenide">пример</a>. Под капотом он использует <a href="https://github.com/jalian-systems/marathonv5">реализацию вебдрайвера для swing</a>.</li> <li>Сильно спорный доклад, но есть полезные идеи: <a href="https://www.youtube.com/watch?v=BzM-VAf8C-c">SPA. React. Selenium vs. Selenide</a></li> <li>5-7 октября снова будет Гейзенбаг - <a href="https://heisenbug-moscow.ru/callforpapers/">подавайте заявки!</a></li> </ul> <p><br /></p> <h1 id="статистика-использования-селенида">Статистика использования Селенида</h1> <center> <img src="/images/2021/08/selenide.downloads.png" width="800" /> </center> <p>249+ тысяч скачиваний в месяц. Чуть-чуть не хватило до 250K.</p> <h3 id="аста-ли-виста-бэйби">Аста ли виста, бэйби!</h3> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2021/08/29/selenide-5.24.0/ http://ru.selenide.org/2021/08/29/selenide-5.24.0 2021-08-29T00:00:00+00:00 Вышла Selenide 5.23.0 <p>Добрый вечер!</p> <p>16 июля вышел релиз <a href="https://github.com/selenide/selenide/milestone/125?closed=1">Selenide 5.23.0</a>.</p> <p>В нём появилось кое-что существенно новое для селенида.</p> <h1 id="проверки-нового-поколения">Проверки нового поколения</h1> <p>Теперь в селениде есть встроенные проверки не только для веб-элементов, но и для некоторых других штук. С автоматическими ожиданиями, понятными сообщениями об ошибках, попаданием в отчёт и т.д. Всё как вы любите.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1442">issue 1442</a>. Спасибо <a href="https://github.com/dbudim">Dmitriy Budim</a> за запуск всей этой эпопеи в <a href="https://github.com/selenide/selenide/pull/1478">PR 1478</a>.</p> <p><br /> Давайте посмотрим, что же это за проверки.</p> <h2 id="проверки-для-url">Проверки для URL</h2> <p>До сих пор в селениде было только два метода, позволяющие получить URL текущей страницы или текущего фрейма (в большинстве случаев это одно и то же).</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">String</span> <span class="n">url1</span> <span class="o">=</span> <span class="nc">WebDriverRunner</span><span class="o">.</span><span class="na">url</span><span class="o">();</span> <span class="nc">String</span> <span class="n">url2</span> <span class="o">=</span> <span class="nc">WebDriverRunner</span><span class="o">.</span><span class="na">currentFrameUrl</span><span class="o">();</span> </code></pre></div></div> <p>Как их проверять, было непонятно. И ещё непонятнее, как дождаться, что нужный урл загрузился.</p> <p>Теперь такие проверки есть:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">Selenide</span><span class="o">.</span><span class="na">webdriver</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">WebDriverConditions</span><span class="o">.*;</span> <span class="n">webdriver</span><span class="o">().</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">url</span><span class="o">(</span><span class="s">"https://auth.google.com"</span><span class="o">));</span> <span class="n">webdriver</span><span class="o">().</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">url</span><span class="o">(</span><span class="s">"https://mastercard.ee"</span><span class="o">),</span> <span class="nc">Duration</span><span class="o">.</span><span class="na">ofSeconds</span><span class="o">(</span><span class="mi">42</span><span class="o">));</span> <span class="n">webdriver</span><span class="o">().</span><span class="na">shouldNotHave</span><span class="o">(</span><span class="n">url</span><span class="o">(</span><span class="s">"http://yandex.ru"</span><span class="o">);</span> <span class="n">webdriver</span><span class="o">().</span><span class="na">shouldNotHave</span><span class="o">(</span><span class="n">urlStartingWith</span><span class="o">(</span><span class="s">"ftp://"</span><span class="o">));</span> <span class="n">webdriver</span><span class="o">().</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">currentFrameUrl</span><span class="o">(</span><span class="n">baseUrl</span> <span class="o">+</span> <span class="s">"/login.html"</span><span class="o">));</span> <span class="n">webdriver</span><span class="o">().</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">currentFrameUrlStartingWith</span><span class="o">(</span><span class="n">baseUrl</span> <span class="o">+</span> <span class="s">"/logout.html"</span><span class="o">));</span> </code></pre></div></div> <p>Каждая из этих проверок:</p> <ol> <li>если надо, подождёт (по умолчанию до 4 секунд)</li> <li>добавится в отчёт (текстовой или аллюр)</li> <li>если урл по истечении 4 секунд не такой - сделает скриншот и кинет ошибку <code class="language-plaintext highlighter-rouge">ConditionNotMetException</code></li> </ol> <p>В лучших традициях селенида можно</p> <ul> <li>переопределять дефалтовый таймаут (4 секунды) на любой другой: <code class="language-plaintext highlighter-rouge">Configuration.timeout = 8000;</code></li> <li>задавать кастомный таймаут (вторым параметром типа <code class="language-plaintext highlighter-rouge">Duration.ofSeconds(42)</code>)</li> <li>создавать свои кастомные проверки (см. <a href="https://github.com/selenide/selenide/blob/c045579f243fb3a5abb99033e440cf8f12caa99c/statics/src/test/java/integration/WebDriverConditionsTest.java#L127">пример</a>)</li> </ul> <h2 id="проверки-для-буфера-обмена">Проверки для буфера обмена</h2> <p>Начиная с версии 5.20.0, в селениде есть метод для доступа к буферу обмена:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Clipboard</span> <span class="n">clipboard</span> <span class="o">=</span> <span class="nc">Selenide</span><span class="o">.</span><span class="na">clipboard</span><span class="o">();</span> </code></pre></div></div> <p>Но если раньше можно было только засунуть и высунуть текст из буфера:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">String</span> <span class="n">foo</span> <span class="o">=</span> <span class="n">clipboard</span><span class="o">().</span><span class="na">getText</span><span class="o">();</span> <span class="n">clipboard</span><span class="o">().</span><span class="na">setText</span><span class="o">(</span><span class="s">"bar"</span><span class="o">);</span> </code></pre></div></div> <p>То теперь его можно проверить - с дефалтовым и кастомным таймаутом, скриншотами и т.д.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">clipboard</span><span class="o">().</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">content</span><span class="o">(</span><span class="s">"Hello fast World"</span><span class="o">));</span> <span class="n">clipboard</span><span class="o">().</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">content</span><span class="o">(</span><span class="s">"Hello slow World"</span><span class="o">),</span> <span class="nc">Duration</span><span class="o">.</span><span class="na">ofMillis</span><span class="o">(</span><span class="mi">1500</span><span class="o">));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/pull/1507">PR 1507</a></p> <h2 id="проверки-для-localstorage">Проверки для <code class="language-plaintext highlighter-rouge">localStorage</code></h2> <p>Начиная с версии 5.15.0, в селениде есть метод <code class="language-plaintext highlighter-rouge">localStorage()</code>, возвращающий объект <code class="language-plaintext highlighter-rouge">LocalStorage</code>.<br /> Но у него были только методы <code class="language-plaintext highlighter-rouge">getItem</code> и <code class="language-plaintext highlighter-rouge">setItem</code>. Опять же, как их проверять и как дождаться нужного значения, было неясно.</p> <p>Теперь ясно:</p> <ul> <li><code class="language-plaintext highlighter-rouge">localStorage().shouldHave(item("cat”));</code></li> <li><code class="language-plaintext highlighter-rouge">localStorage().shouldHave(itemWithValue("mouse", "Jerry”));</code></li> </ul> <p>Кстати, заодно появился метод <code class="language-plaintext highlighter-rouge">localStorage.getItems()</code>, возвращающий всё содержимое в виде мапы.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/1502">PR 1502</a></p> <h2 id="проверки-для-sessionstorage">Проверки для <code class="language-plaintext highlighter-rouge">sessionStorage</code></h2> <p>Всё то же самое, что и про <code class="language-plaintext highlighter-rouge">localStorage</code> - добавились методы</p> <ul> <li><code class="language-plaintext highlighter-rouge">sessionStorage().shouldHave(item("cat”));</code></li> <li><code class="language-plaintext highlighter-rouge">sessionStorage().shouldHave(itemWithValue("mouse", "Jerry”));</code></li> <li><code class="language-plaintext highlighter-rouge">Map&lt;String, String&gt; items = sessionStorage.getItems();</code></li> </ul> <p>См. <a href="https://github.com/selenide/selenide/pull/1502">PR 1502</a></p> <p><br /></p> <h1 id="небольшой-рефакторинг">Небольшой рефакторинг</h1> <p>Мы сделали классы <code class="language-plaintext highlighter-rouge">StaticConfig</code> и <code class="language-plaintext highlighter-rouge">StaticDriver</code> непубличными.<br /> Нам кажется, они никому не должны быть нужны вне селенида. А в ваших проектах они используются? Пишите нам, если у вас развалилась компиляция. :)</p> <h1 id="и-небольшой-багфикс">И небольшой багфикс:</h1> <p>Теперь метод <code class="language-plaintext highlighter-rouge">Selenide.screenshot("filename")</code> снова делает скриншот, даже если настройка <code class="language-plaintext highlighter-rouge">Configuration.screenshots</code> выставлена в <code class="language-plaintext highlighter-rouge">false</code>.</p> <p>Давайте проясним.</p> <ol> <li>Настройку <code class="language-plaintext highlighter-rouge">Configuration.screenshots</code> стоит прописать в <code class="language-plaintext highlighter-rouge">false</code>, если вам не хочется, чтобы селенид автоматически создавал скриншоты при падении тестов. Често говоря, не понимаю, в каких ситуациях это может быть полезно.</li> <li>А вот метод <code class="language-plaintext highlighter-rouge">Selenide.screenshot("filename")</code> можно вызвать в любой момент теста, чтобы явно сделать скриншот, независимо от того, упал тест или не упал. Тоже не очень понимаю, в каких ситуациях это может быть полезно.</li> </ol> <p>Но суть в том, что второй метод работает независимо от первой настройки. Теперь можно выключить автоматические скриншоты, но дёргать их руками только там, где надо.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1477">issue 1477</a> и <a href="https://github.com/selenide/selenide/pull/1506">PR 1506</a></p> <p><br /></p> <h1 id="selenide-selenoid-114">selenide-selenoid 1.1.4</h1> <p>Мы выпустили <a href="https://github.com/selenide/selenide-selenoid/releases/tag/v1.1.4"><code class="language-plaintext highlighter-rouge">selenide-selenoid:1.1.4</code></a> с обновлением на Selenide 5.23.0</p> <p><br /></p> <h1 id="selenide-appium-167">selenide-appium 1.6.7</h1> <p>Мы выпустили <a href="https://github.com/selenide/selenide-appium/releases/tag/v1.6.7"><code class="language-plaintext highlighter-rouge">selenide-appium:1.6.7</code></a> с обновлением на Selenide 5.23.0</p> <p><br /></p> <h1 id="ссылки">Ссылки</h1> <ul> <li>Статья <a href="https://www.appliedtech.ru/vyibor-instrumentov-dlya-ui-testirovaniya-selenium-ili-selenide.html">Selenium или Selenide?</a> в корпоративном блоге “Прикладные Технологии”</li> <li>Статья <a href="https://anilkulkarni.com/2020/03/selenide-ui-tests-in-minutes/">Selenide – UI tests in minutes</a> от Anil Kulkarni</li> </ul> <p><br /></p> <h1 id="статистика">Статистика</h1> <center> <img src="/images/2021/07/selenide.downloads.png" width="800" /> </center> <p>232+ тысяч скачиваний в месяц.</p> <h3 id="беззаботного-лета">Беззаботного лета!</h3> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2021/07/16/selenide-5.23.0/ http://ru.selenide.org/2021/07/16/selenide-5.23.0 2021-07-16T00:00:00+00:00 Вышла Selenide 5.22.3 <p>Добрый вечер!</p> <p>На этом месте был пресс-релиз, который мог больно задеть чувства большого числа наших пользователей и коммитеров. Мы сожалеем, что так получилось, и считаем эту публикацию своей ошибкой, ставшей проявлением непрофессионализма отдельных мейнтейнеров. Никоим образом мы не хотели стать источником раздора и ненависти.</p> <p>Просто обновляйтесь на <a href="https://github.com/selenide/selenide/milestone/126?closed=1">Selenide 5.22.3</a> с самыми свежими и вкусными багфиксами.</p> <h3 id="5223-released-05072021">5.22.3 (released 05.07.2021)</h3> <ul> <li><a href="https://github.com/selenide/selenide/issues/1474">#1474</a> add workaround for NPE in RemoteWebElement.isDisplayed() – see <a href="https://github.com/selenide/selenide/pull/1498">PR #1498</a></li> </ul> <h3 id="5222-released-30062021">5.22.2 (released 30.06.2021)</h3> <ul> <li><a href="https://github.com/selenide/selenide/issues/1493">#1493</a> support uploading files from inside of JAR files – see <a href="https://github.com/selenide/selenide/pull/1494">PR #1494</a></li> <li>fix command <code class="language-plaintext highlighter-rouge">./gradlew</code> - now it installs jars to a local maven repo – see <a href="https://github.com/selenide/selenide/pull/1489">PR #1489</a></li> <li>add support for okhttp 4.9.1 – see <a href="https://github.com/selenide/selenide/pull/1488">PR #1488</a></li> </ul> <h3 id="5221-released-18062021">5.22.1 (released 18.06.2021)</h3> <ul> <li>Add mime type “binary/octet-stream” to download binary files in FireFox</li> </ul> <p><br /></p> <center> <a href="https://www.spletnik.ru/buzz/chronicle/102227-skandal-vokrug-vkusvill-s-lesbiyskoy-paroy-khronologiya-reaktciya.html"> <img src="/images/2021/07/selenide-5.22.3.png" width="800" /> </a> </center> <h3 id="беззаботного-лета">Беззаботного лета!</h3> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2021/07/05/selenide-5.22.3/ http://ru.selenide.org/2021/07/05/selenide-5.22.3 2021-07-05T00:00:00+00:00 Вышла Selenide 5.22.0 <p>Добрый вечер!</p> <p>Лучший подарок - сделанный своими коммитами. <br /> В мой день 40 рождения мы выпустили юбилейный релиз <a href="https://github.com/selenide/selenide/milestone/124?closed=1">Selenide 5.22.0</a>.</p> <p>Развернём упаковку?</p> <p><br /></p> <h1 id="теперь-можно-закрыть-алерт-перед-скачиванием-файла">Теперь можно закрыть алерт перед скачиванием файла</h1> <p>В Селениде есть метод <code class="language-plaintext highlighter-rouge">$.download()</code>, который работает по простому принципу:</p> <ol> <li>Кликни.</li> <li>Подожди, пока в папке появится нужный файл.</li> </ol> <p>Проблема в том, что на некоторых сайтах после клика появляется алерт, который нужно закрыть, чтобы началось скачивание. Ну или вообще, нужно совершить ещё какое-то действие после или вместо клика, чтобы запустить скачивание файла.</p> <p>Теперь можно будет <a href="https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/FileDownloadToFolderTest.java">закрыть алерт</a>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">File</span> <span class="n">downloadedFile</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="n">byText</span><span class="o">(</span><span class="s">"Download me with alert"</span><span class="o">)).</span><span class="na">download</span><span class="o">(</span> <span class="n">using</span><span class="o">(</span><span class="no">FOLDER</span><span class="o">).</span><span class="na">withAction</span><span class="o">(</span> <span class="n">clickAndConfirm</span><span class="o">(</span><span class="s">"Are you sure to download it?"</span><span class="o">)</span> <span class="o">)</span> <span class="o">);</span> </code></pre></div></div> <p>или вообще совершить <a href="https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/FileDownloadViaProxyTest.java">любое нужное действие</a>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">File</span> <span class="n">downloadedFile</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="n">byText</span><span class="o">(</span><span class="s">"Download me with alert"</span><span class="o">)).</span><span class="na">download</span><span class="o">(</span> <span class="n">using</span><span class="o">(</span><span class="no">PROXY</span><span class="o">).</span><span class="na">withAction</span><span class="o">((</span><span class="n">driver</span><span class="o">,</span> <span class="n">link</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="o">{</span> <span class="c1">// add cookies</span> <span class="n">link</span><span class="o">.</span><span class="na">click</span><span class="o">();</span> <span class="c1">// driver.switchTo().window();</span> <span class="c1">// alert.dismiss();</span> <span class="c1">// send http request</span> <span class="c1">// call api</span> <span class="o">}));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1479">issue 1479</a> и <a href="https://github.com/selenide/selenide/pull/1481">PR 1481</a>.</p> <p><br /> <br /></p> <h1 id="доработали-проверку-conditiontextcasesensitive">Доработали проверку <code class="language-plaintext highlighter-rouge">Condition.textCaseSensitive</code></h1> <p>… чтобы она поддерживала выбранные опции в <code class="language-plaintext highlighter-rouge">&lt;select&gt;</code> - по аналогии с <code class="language-plaintext highlighter-rouge">Condition.text</code>.</p> <p>Спасибо <a href="https://github.com/bereg2k">Oleg Berezhnoy</a> за <a href="https://github.com/selenide/selenide/pull/1482">PR 1482</a>.</p> <p><br /> <br /></p> <h1 id="добавили-селекторы-bytextcaseinsensitive-и-withtextcaseinsensitive">Добавили селекторы <code class="language-plaintext highlighter-rouge">byTextCaseInsensitive</code> и <code class="language-plaintext highlighter-rouge">withTextCaseInsensitive</code></h1> <p>… для поиска элемента по тексту, игнорируя регистр.</p> <h3 id="было">Было</h3> <p>В селениде давно есть методы для поиска по тексту.</p> <ul> <li>по полному тексту: <code class="language-plaintext highlighter-rouge">$(byText("Wake up we have a tsar again")</code></li> <li>по подстроке: <code class="language-plaintext highlighter-rouge">$(withText("we have a tsar")</code></li> </ul> <p>Эти селекторы чувствительны к регистру (и внутри используют XPath 1.0).</p> <h3 id="стало">Стало</h3> <p>Теперь же мы добавили аналогичные методы, но нечувствительные к регистру:</p> <ul> <li><code class="language-plaintext highlighter-rouge">$(byTextCaseInsensitive("wake UP we have a TSAR again")</code></li> <li><code class="language-plaintext highlighter-rouge">$(withTextCaseInsensitive("TSAR agAiN")</code></li> </ul> <p>Эти селекторы позволяют искать элементы, игнорируя большие-маленькие буквы.</p> <h3 id="технический-нюанс">Технический нюанс</h3> <p>этот функционал не получилось реализовать с помощью XPath, потому что строковые функции типа <code class="language-plaintext highlighter-rouge">lower-case</code> и <code class="language-plaintext highlighter-rouge">match</code> появились лишь с версии XPath 2.0, а все современные браузеры поддерживают только XPath 1.0. Поэтому пришлось наколбасить <a href="https://github.com/selenide/selenide/blob/master/src/main/resources/find-elements-by-text-case-insensitive.js">хитрый JS код</a> для обхода всего дерева элементов.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1380">issue 1380</a> и <a href="https://github.com/selenide/selenide/pull/1381">PR 1381</a>.</p> <p><br /> <br /></p> <h1 id="добавили-метод-drivergetsessionid">Добавили метод <code class="language-plaintext highlighter-rouge">Driver.getSessionId()</code></h1> <p>По сути он нужен для интеграции с Selenoid.</p> <p>Спасибо <a href="https://github.com/petroOv-PDFfiller">Petro Ovcharenko</a> за <a href="https://github.com/selenide/selenide/pull/1483">PR 1483</a>.</p> <p><br /></p> <h1 id="уменьшили-селенимовские-таймауты">Уменьшили селенимовские таймауты</h1> <p>Внутри селениума прошиты два таймаута, о которых вы, возможно, не догадывались. Проблема в том, что они анормально большие, и их невозможно поменять.</p> <ul> <li>Соединение с вебдрайвером: <code class="language-plaintext highlighter-rouge">connectTimeout</code> = 120000 ms = 2 минуты</li> <li>Запрос к вебдрайверу: <code class="language-plaintext highlighter-rouge">readTimeout</code> = 10800000 ms = 3 часа (!)</li> </ul> <p>Если какая-то операция с вебдрайвером подвисает, то ваш тест будет висеть 3 часа. Ну это же ненормально!<br /> Например, так происходит, когда тестируется приложение на Electron, и оно уходит в трей, а тест пытается сделать скриншот - и надолго зависает.</p> <p>В Selenide 5.22.0 мы добавили возможность <em>менять этот таймаут</em> (под капотом используется жёсткий рефлекшин).<br /> И да, мы сделали дефалтовые значения чуть поменьше (хоть и по-прежнему слишком консервативные):</p> <ul> <li><code class="language-plaintext highlighter-rouge">connectTimeout</code> = 1 минута</li> <li><code class="language-plaintext highlighter-rouge">readTimeout</code> = 2 минуты</li> </ul> <p>Давайте восприниматься это как костыль и надеяться, что в Selenium 4 появится более правильное решение.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/1433">PR 1433</a>.</p> <p><br /></p> <h1 id="selenide-selenoid-113">selenide-selenoid 1.1.3</h1> <p>Мы выпустили обновление <a href="https://github.com/selenide/selenide-selenoid/milestone/4?closed=1"><code class="language-plaintext highlighter-rouge">selenide-selenoid:1.1.3</code></a>, в котором исправили <code class="language-plaintext highlighter-rouge">ClassCastException</code> в некоторых случаях.</p> <p>Спасибо <a href="https://github.com/petroOv-PDFfiller">Petro Ovcharenko</a> за <a href="https://github.com/selenide/selenide-selenoid/pull/10">PR 10</a>.</p> <p><br /></p> <h1 id="selenide-appium-166">selenide-appium 1.6.6</h1> <p>Мы выпустили обновление <a href="https://github.com/selenide/selenide-appium/releases/tag/v1.6.6"><code class="language-plaintext highlighter-rouge">selenide-appium:1.6.6</code></a>, в котором обновились на Selenide 5.22.0</p> <p><br /></p> <h1 id="ссылки">Ссылки</h1> <p>Ого-го! Сразу несколько известных ребят выложили свои видосики про Селенид.</p> <ul> <li>Java champion Sebastian Daschner: <a href="https://www.youtube.com/watch?v=O0-1RhspjAk">Why I switched to using Selenide for UI tests</a></li> <li>JetBrains feat. DJ Юрий Артамонов: <a href="https://www.youtube.com/watch?v=P-vureOnDWY&amp;t=2758s">Modern UI Test Automation with Selenium Libraries</a></li> <li>Статья от JetBrains <a href="https://blog.jetbrains.com/idea/2021/06/live-stream-modern-ui-test-automation-with-selenium-libraries/">про этот стрим</a></li> </ul> <p>И ещё всплыла парочка старых материалов:</p> <ul> <li>Сергей Брит <a href="https://www.youtube.com/watch?v=5WxlKf_EFII">Selenide. Tips and tricks</a>, <a href="https://drive.google.com/file/d/14AUphaV_diRFSE-uUlT9Z_iAtd2uERSu/view">slides</a></li> <li><a href="https://www.slideshare.net/Provectus/selenide-review-and-how-to-start-using-it-in-legacy-selenium-tests">Selenide review</a> by Provectus</li> </ul> <p><br /> И на десерт - молодое поколение учит Селенид:</p> <center> <img src="/images/2021/06/selenide-taffel.png" width="800" /> </center> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2021/06/08/selenide-5.22.0/ http://ru.selenide.org/2021/06/08/selenide-5.22.0 2021-06-08T00:00:00+00:00 Вышла Selenide 5.21.0 <p>Добрый вечер!</p> <p>За окошком месяц май, а на экране релиз <a href="https://github.com/selenide/selenide/milestone/123?closed=1">Selenide 5.21.0</a>.</p> <p><br /></p> <h1 id="убрали-повторные-скриншоты-и-шаги-в-отчёте-для-цепочи-локаторов">Убрали повторные скриншоты и шаги в отчёте для цепочи локаторов</h1> <p>Большинство методов Селенида устроены так, что их можно вызвать несколько штук подряд, в одну строку. Это позволяет писать лаконичные тесты.</p> <p>Что-то вроде</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"table#id"</span><span class="o">).</span><span class="err">$</span><span class="o">(</span><span class="s">"tbody"</span><span class="o">,</span> <span class="mi">2</span><span class="o">).</span><span class="err">$</span><span class="o">(</span><span class="s">"tr.active"</span><span class="o">).</span><span class="err">$</span><span class="o">(</span><span class="s">"td"</span><span class="o">,</span> <span class="mi">5</span><span class="o">)</span> <span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Ну вот"</span><span class="o">))</span> <span class="o">.</span><span class="na">click</span><span class="o">();</span> </code></pre></div></div> <p>Правда, с ними была одна проблема. При падении такой проверки Селенид делал несколько скриншотов, а в отчёт (в т.ч. числе в аллюровский отчёт) добавлялось несколько шагов (один для <code class="language-plaintext highlighter-rouge">"table#id"</code>, второй для <code class="language-plaintext highlighter-rouge">"tbody"</code> и т.д.), хотя по сути это один шаг.</p> <p>Хоть это и некритично, мы эту неприятность убрали. Теперь селенид будет делать один скриншот, а в аллюр отчёте будет одна строка.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1055">issue 1055</a> и <a href="https://github.com/selenide/selenide/pull/1465">PR 1465</a>.</p> <p>NB! Для этого пришлось сделать приличный рефакторинг, и не исключено даже, что что-то могло сломаться. Сообщайте, будем реагировать!</p> <p><br /></p> <h1 id="добавили-browserperteststrategyextension">Добавили BrowserPerTestStrategyExtension</h1> <p>… для перезапуска браузер после каждого теста.</p> <p>По умолчанию Селенид переиспользует браузер между тестами (в рамках одного потока). Это сделано для скорости. Мы предполагаем, что вы сами в начале теста позаботитьесь о том, чтобы обновить страницу, почистить данные и т.п. - ведь это зависит от каждого приложения.</p> <p>Если же вы очень хотите в каждом тесте использовать новый браузер, есть и такая возможность. В Селениде из коробки есть поддерджка для JUnit 4, JUnit 5 и TestNG.</p> <p>Но для JUnit5 у нас был только экстеншн для перезапуска браузера для каждого тестового класса (<code class="language-plaintext highlighter-rouge">@ExtendWith({BrowserStrategyExtension.class}</code>), но не тестового метода.</p> <p>А теперь появился экстенш, заполнивший эту нишу. Если прописать в ваших тестах <code class="language-plaintext highlighter-rouge">@ExtendWith({BrowserPerTestStrategyExtension.class}</code>, то в каждом тестовом методе будет использоваться новый браузер.</p> <p>Это сделает ваши тесты значительно медленнее, но иногда по-другому никак.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1448">issue 1448</a> Спасибо <a href="https://github.com/simple-elf">Anton Aftakhov</a> за <a href="https://github.com/selenide/selenide/pull/1450">PR 1450</a>.</p> <p><br /></p> <h1 id="добавили-метод-hover-со-сдвигом">Добавили метод $.hover() со сдвигом</h1> <p>В селениде давно есть метод <code class="language-plaintext highlighter-rouge">$("div#123").hover()</code> для наведения курсора мыши на нужный элемент. Этот метод двигает курсор к центру элемента, и на это не было возможности повлиять.</p> <p>Теперь же у нас появился метод <code class="language-plaintext highlighter-rouge">$.hover()</code> с параметром, позволяющим указать, на сколько пикселей от центра нужно сдвинуть курсор:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"div#123"</span><span class="o">).</span><span class="na">hover</span><span class="o">(</span><span class="n">withOffset</span><span class="o">(</span><span class="mi">123</span><span class="o">,</span> <span class="mi">122</span><span class="o">));</span> </code></pre></div></div> <p>P.S. Кажется, этот сдвиг не всегда оказывается точным. У меня иногда курсор оказывался <em>примерно</em> в этой позиции плюс-минус 30 пикселей. Делитесь, как у вас?</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1447">issue 1447</a> и <a href="https://github.com/selenide/selenide/pull/1461">PR 1461</a>.</p> <p><br /></p> <h1 id="обновились-на-webdrivermanager-443">Обновились на WebDriverManager 4.4.3</h1> <p>Спасибо <a href="https://github.com/anilreddy">Anil Kumar Reddy Gaddam</a> за <a href="https://github.com/selenide/selenide/pull/1464">PR 1464</a> и <a href="https://github.com/selenide/selenide/pull/1469">PR 1469</a>.</p> <p><br /></p> <h1 id="обновились-javadoc-многих-селенидовских-методов">Обновились javadoc многих селенидовских методов</h1> <p>… касающийся ленивой загрузки и фразы “not recommended”.</p> <p>Теперь javadoc ведёт на эти две статьи в вики:</p> <ul> <li><a href="https://github.com/selenide/selenide/wiki/Lazy-loading">Lazy loading</a></li> <li><a href="https://github.com/selenide/selenide/wiki/Do-not-use-getters-in-tests">Not recommended</a></li> </ul> <p>Внимание, неоднозначный контент.<br /> Возможно, вы захотите подискутировать. <br /> Так давайте подискутируем!</p> <p>См. <a href="https://github.com/selenide/selenide/pull/1430">PR 1430</a></p> <p><br /></p> <h1 id="selenide-selenoid-112">selenide-selenoid 1.1.2</h1> <p>Мы выпустили обновление <a href="https://github.com/selenide/selenide-selenoid/blob/main/CHANGELOG.md"><code class="language-plaintext highlighter-rouge">selenide-selenoid:1.1.2</code></a>, в котором добавили поддержку BasicAuth при скачивании файлов из контейнера Selenoid. <br /> См. <a href="https://github.com/selenide/selenide-selenoid/issues/8">issue 8</a> и <a href="https://github.com/selenide/selenide-selenoid/pull/9">PR 9</a>.</p> <p><br /></p> <h1 id="selenide-appium-165">selenide-appium 1.6.5</h1> <p>Мы выпустили обновление <a href="https://github.com/selenide/selenide-appium/blob/master/CHANGELOG"><code class="language-plaintext highlighter-rouge">selenide-appium:1.6.5</code></a>, в котором улучшили сообщения об ошибках пр падении тестов в iOS.<br /> См. <a href="https://github.com/selenide/selenide-appium/issues/54">issue 54</a>.</p> <p><br /></p> <h1 id="ссылки">Ссылки</h1> <p>Что новенького мы нарыли на просторах сети:</p> <ul> <li>Открытые видеокурсы <a href="https://www.youtube.com/channel/UCVE8_r0VkxUYjGd094sKc4g">Дневник тестировщика</a> - там и про селенид есть несколько выпусков.</li> <li><a href="https://habr.com/ru/company/croc/blog/546430/">Как e2e автотесты на Selenide помогают QA-команде при частых релизах</a></li> <li>годный тред <a href="https://twitter.com/arthicl/status/1366598485252964360?s=20">как слезть с ЛКФ на Селенид</a> (ЛКФ = локальный кривой фреймворк)</li> <li>Пост <a href="https://rieckpil.de/write-concise-web-tests-with-selenide-for-java-projects/">Write Concise Web Tests With Selenide for Java Projects</a> за авторством <a href="https://github.com/rieckpil">Philip Riecks</a>.</li> <li>Видео <a href="https://www.youtube.com/watch?v=T9xns1iMbPI">Введение в Selenide</a> от него же</li> <li>Маленький видеоурок <a href="https://www.youtube.com/watch?v=XPUPirH1yMs">Create Screenshots With Selenide</a> от него же</li> <li>Пример <a href="https://github.com/senpay/layered-test-framework-example-serenity-jbehave">Selenide+Serenity+JBehave</a></li> <li>Пример <a href="https://github.com/sergiomartins8/test-automation-bootstrap/tree/master/ui-tests">Selenide+TestNG+ExtentReports</a></li> <li>курс <a href="https://slifki.info/threads/sergei-semenov-selenium-i-selenide-dlja-nachinajuschix-automation-qa-qc-na-java-2020.85098/">Selenium и Selenide для начинающих</a> (прикольно же!)</li> </ul> <p><br /></p> <h2 id="немного-статистики">Немного статистики</h2> <p>Статистика скачиваний Selenide за апрель 2021:</p> <center> <img src="/images/2021/05/selenide.downloads.png" width="800" /> </center> <p>Чуть-чуть не дотянули до 200 тысяч.</p> <p><br /></p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2021/05/15/selenide-5.21.0/ http://ru.selenide.org/2021/05/15/selenide-5.21.0 2021-05-15T00:00:00+00:00 Вышла Selenide 5.20.1 <p>Добрый вечер!</p> <p>Джо Байдена спросили, считает ли он <code class="language-plaintext highlighter-rouge">$$.as</code> киллер-фичей. «Ммм, хмм, да», — ответил Байден.</p> <p>Это сдвоенный обзор на релиз <a href="https://github.com/selenide/selenide/milestone/118?closed=1">Selenide 5.20.0</a> и <a href="https://github.com/selenide/selenide/milestone/119?closed=1">Selenide 5.20.1</a>.</p> <p><br /></p> <h1 id="добавили-методы-для-операций-с-буфером-обмена">Добавили методы для операций с буфером обмена</h1> <ul> <li><code class="language-plaintext highlighter-rouge">Selenide.clipboard().setText("111");</code></li> <li><code class="language-plaintext highlighter-rouge">assertEquals("Hello World", Selenide.clipboard().getText());</code></li> </ul> <p>Имейте в виду, что на линуксе буфер обмена не будет работать без иксов. Либо запускайте xvfb, либо ещё как-то выкручивайтесь.</p> <p>Спасибо <a href="https://github.com/dbudim">Dmitriy Budim</a> за <a href="https://github.com/selenide/selenide/pull/1409">PR 1409</a>.</p> <p>NB! Эти методы переопределены в плагине <a href="https://github.com/selenide/selenide-selenoid">selenide-selenoid</a>, так что они корректно работают с селеноидом. Для него мы тоже выпустили версию <a href="https://github.com/selenide/selenide-selenoid/releases/tag/v1.1.0">1.1.0</a>.</p> <p><br /></p> <h1 id="добавили-режим-headless-для-браузера-microsoft-edge">Добавили режим headless для браузера Microsoft Edge</h1> <p>Раньше настройка <code class="language-plaintext highlighter-rouge">Configuration.headless</code> срабатывала только для Chrome и Firefox, а теперь ещё и для Edge.</p> <p>(Браузеры IE, Opera и Safari, насколько я знаю, до сих пор не поддерживают headless режим.)</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1422">issue 1422</a> и <a href="https://github.com/selenide/selenide/pull/1424">PR 1424</a>.</p> <p><br /></p> <h1 id="добавили-метод-as-для-задания-алиаса-коллекциям">Добавили метод $$.as() для задания алиаса коллекциям</h1> <p>Как вы помните, в Selenide 5.17.0 мы добавили возможность задавать единичным элементам “понятное” имя. Теперь имя можно задавать и коллекциям:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="nc">By</span><span class="o">.</span><span class="na">xpath</span><span class="o">(</span><span class="s">"/long/ugly/xpath[1][2][3]"</span><span class="o">)).</span><span class="na">as</span><span class="o">(</span><span class="s">"Login button"</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">visible</span><span class="o">);</span> <span class="err">$$</span><span class="o">(</span><span class="nc">By</span><span class="o">.</span><span class="na">xpath</span><span class="o">(</span><span class="s">"/long/ugly/xpath[1][2][3]"</span><span class="o">)).</span><span class="na">as</span><span class="o">(</span><span class="s">"Login buttons"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">size</span><span class="o">(</span><span class="mi">2</span><span class="o">));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1389">issue 1389</a> и <a href="https://github.com/selenide/selenide/pull/1431">PR 1431</a>.</p> <p>NB! Не торопитесь использовать эту возможность. Лично я воспринимаю её как “хак последней надежды”.<br /> В отчёте всегда лучше видеть настоящий локатор, чем кем-то придуманное имя, которое всегда может оказаться:</p> <ul> <li>Обманчивым</li> <li>Устаревшим</li> <li>Вводящим в заблуждение</li> </ul> <p>Лучше инвестируйте свои усилия в то, чтобы использовать читаемые локаторы. Ну и грамотно называть переменные и методы. Вот где сила, брат!</p> <p><br /></p> <h1 id="добавили-проверку-для-коллекций-containexacttextscasesensitive">Добавили проверку для коллекций <code class="language-plaintext highlighter-rouge">containExactTextsCaseSensitive</code></h1> <p>Существующий метод <code class="language-plaintext highlighter-rouge">$$.shouldHave(texts("a", "b", "c"))</code> проверяет, что в коллекции ровно эти элементы и никаких больше. А иногда хочется менее строгой проверки. Например, нужно проверить, что в списке торгуемых валют точно есть RUB, EUR, USD - и какие угодно ещё.</p> <p>Теперь для этого есть метод:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$$</span><span class="o">.</span><span class="na">should</span><span class="o">(</span><span class="n">containTexts</span><span class="o">(</span><span class="s">"RUB"</span><span class="o">,</span> <span class="s">"EUR"</span><span class="o">,</span> <span class="s">"USD"</span><span class="o">));</span> </code></pre></div></div> <p>Спасибо <a href="https://github.com/bereg2k">Oleg Berezhnoy</a> за <a href="https://github.com/selenide/selenide/pull/1426">PR 1426</a>.</p> <p><strong>UPD</strong> В оперативно вышедшей Selenide 5.20.1 его переименовали в</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$$</span><span class="o">.</span><span class="na">should</span><span class="o">(</span><span class="n">containExactTextsCaseSensitive</span><span class="o">(</span><span class="s">"RUB"</span><span class="o">,</span> <span class="s">"EUR"</span><span class="o">,</span> <span class="s">"USD"</span><span class="o">));</span> </code></pre></div></div> <p>Спасибо <a href="https://github.com/bereg2k">Oleg Berezhnoy</a> за <a href="https://github.com/selenide/selenide/pull/1438">PR 1438</a> и <a href="https://github.com/selenide/selenide/pull/1439">PR 1439</a>.</p> <p><br /></p> <h1 id="починили-утерянные-опции-firefoxoptions">Починили утерянные опции FirefoxOptions</h1> <p>В некоторых ситуации некоторые настройки Firefox терялись, теперь не теряются. Опции нашлись.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1436">issue 1436</a>. Спасибо <a href="https://github.com/dbudim">Dmitriy Budim</a> за <a href="https://github.com/selenide/selenide/pull/1437">PR 1437</a>.</p> <p><br /></p> <h1 id="убрали-логирование-поисковых-методов">Убрали логирование “поисковых” методов</h1> <p>В SelenideElement есть несколько методов для поиска других элементов:</p> <ul> <li><code class="language-plaintext highlighter-rouge">$.findAll()</code></li> <li><code class="language-plaintext highlighter-rouge">$.parent()</code></li> <li><code class="language-plaintext highlighter-rouge">$.sibling()</code></li> <li><code class="language-plaintext highlighter-rouge">$.preceding()</code></li> <li><code class="language-plaintext highlighter-rouge">$.lastChild()</code></li> <li><code class="language-plaintext highlighter-rouge">$.closest()</code></li> </ul> <p>Такие методы оказывались в отчёте дважды: сначала при их вызове, а потом - при вызове любого метода на найденном элементе. Теперь мы это дублирование убрали.</p> <p>Спасибо <a href="https://github.com/fokinp">Pavel Fokin</a> за <a href="https://github.com/selenide/selenide/pull/1428">PR 1428</a>.</p> <p><br /></p> <p><br /></p> <h3 id="доска-объявлений">Доска объявлений</h3> <p>Ура, новый сезон конференций открыт! Буквально через неделю-две начинается:</p> <ul> <li>У кого нет денег на Heisenbug и JPoint - приходите 27 марта на бесплатный <a href="https://techtrain.ru/2021/spring/schedule/">фестиваль TechTrain</a>, программа там очень многообещающая. <ul> <li>Я, например, планирую послушать “<a href="https://techtrain.ru/2021/spring/talks/4vehn9kwvjg7uzjjbp0nl4/">Что мобильным разработчикам в IT-индустрии неведомо</a>”</li> <li>и “<a href="https://techtrain.ru/2021/spring/talks/1vtaygqjny9w3folebliqv/">Ловушки коллективного владения кодом</a>”.</li> <li>И конечно, “<a href="https://techtrain.ru/2021/spring/talks/74akccvzvqirxg2jbh4t3m/">Какие тулы ты бы взял на удаленку</a>” от ведущих “Ошибки выжившего” Севы и Артёма обещает стать хитом.</li> </ul> </li> <li> <p>А 6-9 апреля грядёт наш любимый <a href="https://heisenbug-piter.ru/2021/spb/schedule/">Heisenbug</a>.</p> <p>У меня там будет заключительный доклад эпопеи про флейки тесты “<a href="https://heisenbug-piter.ru/2021/spb/talks/4wcc3dephlxuzc87wgwkk7/">Flaky tests. Метод</a>” и продолжение мастер-класса “<a href="https://heisenbug-piter.ru/2021/spb/talks/8p4qtsit5rqgga8yuxz5a/">Как начать свой проект автоматизации с нуля</a>”.</p> <p>А послушать я хочу как минимум мастер-класс гуру юзабилити Виталия Фридмана “<a href="https://heisenbug-piter.ru/2021/spb/talks/5lxiyz5rdanigu1wuaujtt/">От birthday selector до inline validation: Всё, что нужно знать о веб-формах</a>” и много чего ещё вкусненького.</p> </li> <li> <p>А 13-17 апреля пройдёт конференция <a href="https://jpoint.ru/2021/schedule/">JPoint</a></p> <p>Она скорее для разработчиков, и на ней я тоже успею засветиться в <a href="https://jpoint.ru/2021/talks/5gmcsxserjfhlzgt9dpfq3/">мастер-классе по парному программированию</a>.</p> </li> <li> <p>А ещё 29 мая будет новосибирский <a href="https://11.codefest.ru/">Codefest</a></p> <p>Там у меня будет доклад про “<a href="https://11.codefest.ru/lecture/1751">Трюки с javascript в автотестах</a>”.</p> </li> </ul> <p>Приходите, всё равно ж делать нечего на карантине!</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2021/03/23/selenide-5.20.1/ http://ru.selenide.org/2021/03/23/selenide-5.20.1 2021-03-23T00:00:00+00:00 Вышла Selenide 5.19.0 <p>Всем привет!</p> <p>Вы, наверное, не знали, но сегодня, 24 февраля, в Эстонии чуть ли не главный праздник - <a href="https://ru.wikipedia.org/wiki/%D0%94%D0%B5%D0%BD%D1%8C_%D0%BD%D0%B5%D0%B7%D0%B0%D0%B2%D0%B8%D1%81%D0%B8%D0%BC%D0%BE%D1%81%D1%82%D0%B8_%D0%AD%D1%81%D1%82%D0%BE%D0%BD%D0%B8%D0%B8">День Независимости</a>. Ровно 103 года назад Эстония была провозглашена независимым демократическим государством.</p> <p>А спустя 93 года в Эстонии, в казематах компании <a href="https://codeborne.com/">Codeborne</a> родилась библиотека Selenide. Это ли не чудо?</p> <p>Дню независимости мы и посвящаем наш новый релиз <a href="https://github.com/selenide/selenide/milestone/116?closed=1">Selenide 5.19.0</a>.</p> <p><br /></p> <h1 id="наконец-таки-починили-draganddrop">Наконец-таки починили drag’and’drop</h1> <p>В селениде уже давно есть метод <code class="language-plaintext highlighter-rouge">$.dragAndDropTo()</code>, но он фактически не работает. Под капотом он использует селениумовский механизм <code class="language-plaintext highlighter-rouge">Actions</code>, и что-то там явно сломано. Ну не тащит элемент и всё.</p> <p>А теперь мы запилили альтернативную реализацию с помощью JavaScript. И она, похоже, работает во всех браузерах. Поэтому мы даже включили её по умолчанию.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="c1">// Рабочий вариант:</span> <span class="err">$</span><span class="o">(</span><span class="s">"#drag1"</span><span class="o">).</span><span class="na">dragAndDropTo</span><span class="o">(</span><span class="s">"#div2"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#drag1"</span><span class="o">).</span><span class="na">dragAndDropTo</span><span class="o">(</span><span class="s">"#div2"</span><span class="o">,</span> <span class="n">usingJavaScript</span><span class="o">());</span> <span class="c1">// Нерабочий вариант через Actions (ну вдруг он у вас почему-то работает):</span> <span class="err">$</span><span class="o">(</span><span class="s">"#drag1"</span><span class="o">).</span><span class="na">dragAndDropTo</span><span class="o">(</span><span class="s">"#div2"</span><span class="o">,</span> <span class="n">usingActions</span><span class="o">());</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1110">issue 1110</a>.</p> <p>Спасибо <a href="https://github.com/dbudim">Dmitriy Budim</a> за <a href="https://github.com/selenide/selenide/pull/1412">PR 1412</a>.</p> <p><br /></p> <h1 id="поддержка-appium">Поддержка Appium</h1> <p>Заодно мы выпустили и обновление библиотеки <code class="language-plaintext highlighter-rouge">selenide-appium:1.6.2</code>, в которой метод <code class="language-plaintext highlighter-rouge">$.dragAndDropTo()</code>, теперь переопределён, так что он работает и на мобильниках. См. <a href="https://github.com/selenide/selenide-appium/pull/53/files">PR #53</a>.</p> <p><br /></p> <h1 id="починили-метод-clickusingjavascript-в-internet-explorer">Починили метод <code class="language-plaintext highlighter-rouge">$.click(usingJavascript())</code> в Internet Explorer</h1> <p>См. <a href="https://github.com/selenide/selenide/issues/1406">issue 1406</a> и <a href="https://github.com/selenide/selenide/pull/1419">PR 1419</a>.</p> <p><br /></p> <h1 id="улучшили-описание-коллекции-snapshot">Улучшили описание коллекции <code class="language-plaintext highlighter-rouge">$$.snapshot()</code></h1> <p>У селенидовских коллекций есть один хитрый метод <code class="language-plaintext highlighter-rouge">$$.snapshot()</code>. Он запоминает текущее состоние коллекции, и при дальнейших обращениях не загружает её заново из браузера. Это полезно для ускорения тестов, когда коллекция большая, и вы уверены, что её элементы уже точно не изменятся.</p> <p>С ними была только маленькая проблемка: в отчётах выглядело не слишком красиво. Например, такая строка:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$$</span><span class="o">(</span><span class="s">"#root li"</span><span class="o">).</span><span class="na">snapshot</span><span class="o">().</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">size</span><span class="o">(</span><span class="mi">3</span><span class="o">))</span> </code></pre></div></div> <p>при падении в отчёте выглядела как</p> <blockquote> <p>List size mismatch: expected: = 3, actual: 2, collection: $$(2 elements)</p> </blockquote> <p>Как видите, в описании нет селектора оригинальной коллекции, только <code class="language-plaintext highlighter-rouge">(2 elements)</code>.</p> <p>Теперь виден и селектор:</p> <blockquote> <p>List size mismatch: expected: = 3, actual: 2, collection: #root li.snapshot(2 elements)</p> </blockquote> <p>Спасибо <a href="https://github.com/fokinp">Pavel Fokin</a> за <a href="https://github.com/selenide/selenide/pull/1402">PR 1402</a>.</p> <p><br /></p> <h1 id="добавили-метод-getalias">Добавили метод <code class="language-plaintext highlighter-rouge">$.getAlias()</code></h1> <p>Он возвращает то, что вы сами же задали с помощью <code class="language-plaintext highlighter-rouge">$.as("login button")</code>. В обычных тестах этот метод не должен быть нужен. Но может понадобиться, если вы пилите какой-то свой хитрый отчёт. Ну мало ли, убийцу Аллюра…</p> <p>Спасибо <a href="https://github.com/pavelpp">pavelpp</a> за <a href="https://github.com/selenide/selenide/pull/1415">PR 1415</a>.</p> <p><br /></p> <h1 id="добавили-события-refresh-и-тп-в-селенидовский-лог">Добавили события “refresh” и т.п. в селенидовский лог</h1> <p>В селениде есть целый ряд методов, которые не связаны явно в веб-элементами (<code class="language-plaintext highlighter-rouge">refresh()</code>, <code class="language-plaintext highlighter-rouge">back()</code> и т.п.) И мы в какой-то момент обнаружили, что некоторые из них не отображались в отчёта Selenide или Allure. Несмертельно, конечно, но всё-таки зачем-то ведь эти отчёты кому-то нужны…</p> <p>Теперь мы исправили эту оплошность, и следующие методы будут исправно красоваться в отчётах:</p> <ul> <li><code class="language-plaintext highlighter-rouge">refresh</code></li> <li><code class="language-plaintext highlighter-rouge">back</code></li> <li><code class="language-plaintext highlighter-rouge">forward</code></li> <li><code class="language-plaintext highlighter-rouge">updateHash</code></li> <li><code class="language-plaintext highlighter-rouge">confirm</code></li> <li><code class="language-plaintext highlighter-rouge">dismiss</code></li> <li><code class="language-plaintext highlighter-rouge">prompt</code></li> <li><code class="language-plaintext highlighter-rouge">clearCookies</code></li> </ul> <p>См. <a href="https://github.com/selenide/selenide/issues/1383">issue 1383</a> и <a href="https://github.com/selenide/selenide/pull/1404">PR 1404</a>.</p> <p><br /></p> <h1 id="добавили-аннотаций-nullable-методам-класса-webdriverrunner">Добавили аннотаций <code class="language-plaintext highlighter-rouge">@Nullable</code> методам класса <code class="language-plaintext highlighter-rouge">WebDriverRunner</code></h1> <p>Самым важным, по-видимому, тут является метод <code class="language-plaintext highlighter-rouge">WebDriverRunner.getSelenideProxy()</code> - не было очевидно, что он может возвращать <code class="language-plaintext highlighter-rouge">null</code>, если прокси не запущен.</p> <p>Теперь такая ошибка будет подсвечиваться в IDE жёлтеньким.</p> <p>См. <a href="https://github.com/selenide/selenide/commit/9b4723d090442c">коммит</a>.</p> <p><br /></p> <h1 id="починили-тесты-селенида-на-не-англоязычных-машинах">Починили тесты селенида на не-англоязычных машинах</h1> <p>Оказалось, что парочка собственных тестов селенида падали, если их запустить на машине, на которой системным языком был выбран не английский, а скажем, французкий или испанский. Оказывается, в этих странах иначе форматируют Duration.</p> <p>Теперь тесты исправлены, и по идее такое больше не может повториться.</p> <p>Спасибо <a href="https://github.com/vrossellotravelc">Vicente Rossello Jaume</a> за <a href="https://github.com/selenide/selenide/pull/1408">PR 1408</a>.</p> <p><br /></p> <h1 id="статистика">Статистика</h1> <p>Свежая статистика по скачкам Селенида:</p> <center> <img src="/images/2021/02/selenide.downloads.png" width="800" /> </center> <p><br /></p> <h1 id="традиции">Традиции</h1> <p>Ну вот и всё на сегодня.</p> <p>Вы обновляйтесь, а я пока пойду найду стопки водки и бутерброд с килькой. Традиция, ничего не поделаешь.</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2021/02/24/selenide-5.19.0/ http://ru.selenide.org/2021/02/24/selenide-5.19.0 2021-02-24T00:00:00+00:00 Вышла Selenide 5.18.1 <p>Всем привет!</p> <p>Как сказал бы рэпер Гнойный, “релизай, а не накапливай!”<br /> Вот и мы релизнули небольшое обновление <a href="https://github.com/selenide/selenide/milestone/115?closed=1">Selenide 5.18.1</a>.</p> <p>Давайте заглянем туда с фонариком:</p> <p><br /></p> <h1 id="добавили-метод-selenidegetsessionstorage">Добавили метод <code class="language-plaintext highlighter-rouge">Selenide.getSessionStorage()</code></h1> <p>по аналогии с <code class="language-plaintext highlighter-rouge">Selenide.getLocalStorage()</code>, который появился ранее в версии 5.15.0.</p> <p>У них одинаковый набор методов: <code class="language-plaintext highlighter-rouge">getItem</code>, <code class="language-plaintext highlighter-rouge">setItem</code>, <code class="language-plaintext highlighter-rouge">removeItem</code>, <code class="language-plaintext highlighter-rouge">clear</code> и т.д.</p> <blockquote> <p>Иногда полезно положить <code class="language-plaintext highlighter-rouge">sessionStorage</code> или <code class="language-plaintext highlighter-rouge">localStorage</code>, скажем, хитрый флаг, чтобы эмулировать какое-нибудь действие пользователя или включить-выключить какие-то фичи или настройки.</p> </blockquote> <p>Спасибо <a href="https://github.com/dbudim">Dmitriy Budim</a> за <a href="https://github.com/selenide/selenide/pull/1400">PR 1400</a>.</p> <p>P.S. Для справки, <a href="https://itchief.ru/javascript/localstorage-and-sessionstorage">разница между localStorage и sessionStorage</a>.</p> <p><br /></p> <h1 id="исправили-сообщение-об-ошибке-для-filterbyand">Исправили сообщение об ошибке для <code class="language-plaintext highlighter-rouge">$$.filterBy(and(..))</code></h1> <p>Как вы знаете, селенид предоставляет богатые возможности для фильтрации и проверки коллекций.</p> <p>Но пользователь <a href="https://github.com/fokinp">Pavel Fokin</a> обнаружил, что сообщение об ошибке может выглядеть непонятно, когда коллекция фильтруется по <code class="language-plaintext highlighter-rouge">and</code> условию, т.е. комбинации нескольких разных условий:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$$</span><span class="o">(</span><span class="s">".sofa"</span><span class="o">).</span><span class="na">filterBy</span><span class="o">(</span><span class="n">and</span><span class="o">(</span><span class="s">"shining"</span><span class="o">,</span> <span class="n">text</span><span class="o">(</span><span class="s">"Jorshik"</span><span class="o">),</span> <span class="n">text</span><span class="o">(</span><span class="s">"Zoloto"</span><span class="o">))).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">size</span><span class="o">(</span><span class="mi">2</span><span class="o">));</span> </code></pre></div></div> <p><br /></p> <p>Результат был не совсем логичный (он содержал лишь последнее проверенное условие):</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">...</span> <span class="nl">collection:</span> <span class="o">.</span><span class="na">sofa</span><span class="o">.</span><span class="na">filter</span><span class="o">(</span><span class="n">text</span> <span class="nc">Jorshik</span><span class="o">)</span> </code></pre></div></div> <p>А теперь результат более корректный (он содержит все условия):</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">...</span> <span class="nl">collection:</span> <span class="o">.</span><span class="na">sofa</span><span class="o">.</span><span class="na">filter</span><span class="o">(</span><span class="nl">shining:</span> <span class="n">text</span> <span class="err">'</span><span class="nc">Jorshik</span><span class="err">'</span> <span class="n">and</span> <span class="n">text</span> <span class="err">'</span><span class="nc">Zoloto</span><span class="err">'</span><span class="o">)</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1392">issue 1392</a>.<br /> Спасибо <a href="https://github.com/fokinp">Pavel Fokin</a> за <a href="https://github.com/selenide/selenide/pull/1393">PR 1393</a>.</p> <p><br /></p> <h1 id="передаём-настройку-noproxy-от-внешнего-прокси-селенидовскому">Передаём настройку “noproxy” от внешнего прокси селенидовскому</h1> <p>Бывает, что селенид запускается и со своим собственным прокси, и с прокси пользователя.</p> <p>У прокси есть одна особенная настройка “noproxy”, и туда часто пихают “localhost”. Это значит, что через прокси должны ходить все запросы, кроме “http://localhost:*”. Так вот, в случае с “двойным” прокси эта настройка терялась, и селенид не мог выполнить запросы на localhost.</p> <p><em>Напрямую, а не через прокси.</em></p> <p><em>Локалхост - нежная штучка!</em></p> <p>Спасибо <a href="https://github.com/BorisOsipov">Boris Osipov</a> за <a href="https://github.com/selenide/selenide/pull/1390">PR 1390</a>.</p> <p><br /></p> <h1 id="обновились-на-netty-4159final-и-littleproxy-202">Обновились на Netty 4.1.59.Final и LittleProxy 2.0.2</h1> <p>Вряд ли вы будете читать, но вот релизноутсы <a href="https://netty.io/news/2021/02/08/4-1-59-Final.html">Netty 4.1.59.Final</a> и <a href="https://github.com/mrog/LittleProxy/blob/master/RELEASE_NOTES.md">LittleProxy 2.0.2</a>. Как минимум там исправили какие-то утечки памяти и дыру в безопасности.</p> <h2 id="читальня">Читальня</h2> <p>Организаторы Гейзенбага выложили видосики с осеннего Heisenbug Moscow 2020.<br /> Из того, что я успел заметить:</p> <ul> <li><a href="https://www.youtube.com/watch?list=PLsVTVVvrKX9tBV0_LSkAoSZge3C8qb0ec&amp;v=fFe3reCoeBQ&amp;feature=emb_logo&amp;ab_channel=Heisenbug">Flaky tests. Порядок имеет значение</a> / Андрей Солнцев</li> <li>Воркшоп “Как начать свой проект автоматизации с нуля”: <a href="https://www.youtube.com/watch?v=1aq4gYflEho&amp;feature=youtu.be&amp;utm_campaign=Heisenbug_2020_Piter_Announce_NoParticipants_211220&amp;utm_medium=email&amp;utm_source=newsletter&amp;ab_channel=Heisenbug">часть 1</a>, <a href="https://www.youtube.com/watch?utm_campaign=Heisenbug_2020_Piter_Announce_NoParticipants_211220&amp;utm_medium=email&amp;utm_source=newsletter&amp;v=pbvJ8rmh7Ws&amp;feature=youtu.be&amp;ab_channel=Heisenbug">часть 2</a> / Андрей Солнцев, Юрий Артамонов</li> <li><a href="https://www.youtube.com/watch?v=4yq37nxkguM&amp;list=PLsVTVVvrKX9tBV0_LSkAoSZge3C8qb0ec&amp;index=12&amp;ab_channel=Heisenbug">Серверный античит: Панацея или рудимент?</a> / Евгений Ченцов, Евгений Крутских</li> <li><a href="https://www.youtube.com/watch?v=8gOkdFk2JZ8&amp;list=PLsVTVVvrKX9tBV0_LSkAoSZge3C8qb0ec&amp;index=3&amp;ab_channel=Heisenbug">Типы автоматического тестирования в IntelliJ IDEA</a> / Юрий Артамонов</li> <li><a href="https://www.youtube.com/watch?v=Prm2-c_5mYs&amp;list=PLsVTVVvrKX9tBV0_LSkAoSZge3C8qb0ec&amp;index=18&amp;ab_channel=Heisenbug">Тест-кейсы как код</a> / Артем Ерошенко</li> </ul> <p><br /></p> <p>Вот и всё на сегодня. Обновляйтесь и делитесь впечатлениями. Заводите баги <a href="https://github.com/selenide/selenide/issues/new">на гитхабе</a>, жалуйтесь <a href="https://softwaretesters.slack.com/messages/selenide_ru">в чатиках</a>, материтесь <a href="https://twitter.com/selenide">в твиттере</a>.</p> <p><br /> <em>Опенсорс сильнее багов!</em></p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2021/02/11/selenide-5.18.1/ http://ru.selenide.org/2021/02/11/selenide-5.18.1 2021-02-11T00:00:00+00:00 Вышла Selenide 5.18.0 <p>Ура, товарищи!</p> <p>На дворе 23 января.</p> <p>Несанкционированные релизы сейчас запрещены, поэтому сегодня у нас просто негативное падение номера версии. Обновляйтесь: <a href="https://github.com/selenide/selenide/milestone/113?closed=1">Selenide 5.18.0</a>.</p> <p>Приглашаю вас на маленькую виртуальную экскурсию по изменениям в 5.18.0.<br /> Устраивайтесь поудобнее.</p> <p><br /></p> <h1 id="выключили-логи-вебдрайвера-по-умолчанию">Выключили логи вебдрайвера по умолчанию</h1> <p>Начиная с версии 5.13.0, Selenide писал логи вебдрайвера в файлы <code class="language-plaintext highlighter-rouge">build/reports/tests/webdriver.uuid.log</code>.<br /> Тогда это казалось полезным, но оказалось, что логи эти занимают довольно много места и особо никого не интересуют. Поэтому мы всё-таки решили не включать их по умолчанию.</p> <p><em>Логи вебдрайвера отправляются в комнату для мусора.</em></p> <p>Если надо, вы всегда можете включить эти логи настройкой<br /> <code class="language-plaintext highlighter-rouge">Configuration.webdriverLogsEnabled = true</code>.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1365">issue 1365</a> и <a href="https://github.com/selenide/selenide/pull/1379">PR 1379</a>.</p> <p><br /></p> <h1 id="заменили-тип-параметра-timeout-с-long-на-duration">Заменили тип параметра “timeout” с Long на Duration</h1> <p>… в методах коллекций. Теперь вместо</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$$</span><span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">texts</span><span class="o">(...),</span> <span class="mi">5000</span><span class="o">);</span> </code></pre></div></div> <p>модно будет писать</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$$</span><span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">texts</span><span class="o">(...),</span> <span class="nc">Duration</span><span class="o">.</span><span class="na">ofSeconds</span><span class="o">(</span><span class="mi">5</span><span class="o">));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1377">issue 1377</a>.<br /> Спасибо <a href="https://github.com/ostap-oleksyn">Ostap Oleksyn</a> за <a href="https://github.com/selenide/selenide/pull/1377">PR 1377</a>.</p> <p><br /></p> <h1 id="ускорили-поиск-вложенных-элементов-в-shadow-dom">Ускорили поиск вложенных элементов в shadow dom</h1> <p>Одна из фич, которые есть Selenide, но нет в Selenium webdriver - это <a href="/2020/03/18/selenide-5.10.0/"><em>shadow dom</em></a>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="n">shadowCss</span><span class="o">(</span><span class="s">"p"</span><span class="o">,</span> <span class="s">"#shadow-host"</span><span class="o">,</span> <span class="s">"#inner-shadow-host"</span><span class="o">))</span> <span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"The Shadow-DOM inside another shadow tree"</span><span class="o">));</span> </code></pre></div></div> <p>В дереве DOM может быть сколько угодно <em>shadow root</em> внутри других <em>shadow root</em>.</p> <p>Чтобы найти все элементы внутри всех вложенных shadow root, метод <code class="language-plaintext highlighter-rouge">$(shadowCss())</code> вызывал в цикле<br /> хитрый JavaScript код для каждого shadow root по отдельности. И это может быть медленно, потому что каждый вызов webdriver занимает время.</p> <p>Теперь <code class="language-plaintext highlighter-rouge">$(shadowCss())</code> дёргает <a href="https://github.com/selenide/selenide/blob/master/src/main/resources/find-in-shadow-roots.js">ещё более хитрый рекурсивный JavaScript</a>, который находит все элементы во всех shadow dom за один вызов.</p> <p>См. <a href="https://github.com/selenide/selenide/pull/1373">PR 1373</a>.</p> <p>Отдельное спасибо <a href="https://github.com/sakamoto66">sakamoto66</a> за <a href="https://github.com/selenide/selenide/issues/1246">issue 1246</a> и <a href="https://github.com/selenide/selenide/pull/1233">PR 1233</a>. К сожалению, он не был влит, но дал нам пищу для размышлений.</p> <p><br /></p> <h1 id="исправили-проверки-shouldnotand-и-shouldnotor">Исправили проверки <code class="language-plaintext highlighter-rouge">$.shouldNot(and(...))</code> и <code class="language-plaintext highlighter-rouge">$.shouldNot(or(...))</code></h1> <p>Пользователь <a href="https://github.com/pavelpp">pavelpp</a> обнаружил в селениде багу, комбинируя <code class="language-plaintext highlighter-rouge">not</code> с условиями <code class="language-plaintext highlighter-rouge">and</code> и <code class="language-plaintext highlighter-rouge">or</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">".lolkek"</span><span class="o">).</span><span class="na">shouldNotBe</span><span class="o">(</span><span class="n">visible</span><span class="o">,</span> <span class="n">ofSeconds</span><span class="o">(</span><span class="mi">5</span><span class="o">));</span> <span class="c1">// работает</span> <span class="err">$</span><span class="o">(</span><span class="s">".lolkek"</span><span class="o">).</span><span class="na">shouldNotBe</span><span class="o">(</span><span class="n">and</span><span class="o">(</span><span class="s">"foo"</span><span class="o">,</span> <span class="n">visible</span><span class="o">));</span> <span class="c1">// падает</span> <span class="err">$</span><span class="o">(</span><span class="s">".lolkek"</span><span class="o">).</span><span class="na">shouldNotBe</span><span class="o">(</span><span class="n">or</span><span class="o">(</span><span class="s">"foo"</span><span class="o">,</span> <span class="n">visible</span><span class="o">));</span> <span class="c1">// падает</span> </code></pre></div></div> <p>Не отвертишься. Пришлось чинить.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1369">issue 1369</a> и <a href="https://github.com/selenide/selenide/pull/1370">PR 1370</a>.</p> <p>Кстати, мы запретили <code class="language-plaintext highlighter-rouge">and</code> и <code class="language-plaintext highlighter-rouge">or</code> только с одним условием. То есть теперь строка <code class="language-plaintext highlighter-rouge">or("foo", visible)</code> не скомпилируется. Придётся написать как минимум два условия: <code class="language-plaintext highlighter-rouge">or("foo", visible, enabled)</code>.</p> <p>Согласитесь, это логично. <em>Зачем нам выбор из одного?</em></p> <p><br /></p> <h1 id="обнаруживаем-конфликт-в-настройке-browsername">Обнаруживаем конфликт в настройке “browserName”</h1> <p>Так уж вышло, что для задания браузера есть две разных настройки:</p> <ol> <li>Главная - <code class="language-plaintext highlighter-rouge">Configuration.browser</code></li> <li>Другая - <code class="language-plaintext highlighter-rouge">Configuration.browserCapabilities["browserName"]</code> (не знаю, зачем она вообще нужна)</li> </ol> <p>И у вас может открыться неожиданный браузер, если вы не задали первую, но задали вторую. В общем, теперь селенид обнаруживает такой конфликт и сразу кидает ошибку, чтобы всем всё стало понятно:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">IllegalArgumentException:</span> <span class="nc">Conflicting</span> <span class="n">browser</span> <span class="nl">name:</span> <span class="err">'</span><span class="n">chrome</span><span class="err">'</span> <span class="n">vs</span><span class="o">.</span> <span class="err">'</span><span class="n">firefox</span><span class="err">'</span> </code></pre></div></div> <p>Подчёркиваю: настройки <code class="language-plaintext highlighter-rouge">Configuration.browser</code> должно хватать во всех случаях, поэтому вторую не надо никуда пихать.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1366">issue 1366</a> и <a href="https://github.com/selenide/selenide/pull/1374">PR 1374</a>.</p> <p><br /></p> <h1 id="починили-показ-таймаута-в-отчёте">Починили показ таймаута в отчёте</h1> <p>Недавно мы добавили в методы <code class="language-plaintext highlighter-rouge">$.should*</code> параметр <code class="language-plaintext highlighter-rouge">timeout</code> с типом <code class="language-plaintext highlighter-rouge">Duration</code>. А потом оказалось, что он непонятно отображался в отчётах.<br /> Например, строка <code class="language-plaintext highlighter-rouge">$("h1").shouldBe(visible, Duration.ofSeconds(1))</code> в отчёте выглядела так:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"h1"</span><span class="o">)</span> <span class="n">should</span> <span class="nf">be</span><span class="o">([</span><span class="n">visible</span><span class="o">,</span> <span class="no">PT1M</span><span class="o">])</span> </code></pre></div></div> <p>И хотя эта “PT1M” на самом деле отвечает стандарту ISO и означает “time period 1 minute”, мы всё же заменили её на более понятные “300 ms”, “1s”, “1.500 s.” и т.п.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1376">issue 1376</a> и <a href="https://github.com/selenide/selenide/pull/1378">PR 1378</a>.</p> <p><br /></p> <h1 id="обновились-на-webdrivermanager-431">Обновились на WebDriverManager 4.3.1</h1> <p>Как обычно, изменения описаны <a href="https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md">здесь</a>.</p> <p><br /></p> <p>Вот и всё на сегодня. Обновляйтесь и делитесь впечатлениями. Заводите баги <a href="https://github.com/selenide/selenide/issues/new">на гитхабе</a>, жалуйтесь <a href="https://softwaretesters.slack.com/messages/selenide_ru">в чатиках</a>, материтесь <a href="https://twitter.com/selenide">в твиттере</a>.</p> <p><br /></p> <h2 id="читальня">Читальня</h2> <p>На хабре вышла расшифровка доклада <a href="https://habr.com/ru/company/jugru/blog/537166/">“Как законтрибьютить в опенсорс, чтобы не сгореть со стыда”</a> со смачной картинкой Мастера Йоды. Этот доклад мы с Артёмом Ерошенко делали на фестивале TechTrain осенью 2020.</p> <p>По ссылке и текст, и видео: кому что больше нравится.</p> <center> <img src="https://habrastorage.org/webt/ry/y2/bn/ryy2bn6_cjot2q7dipqjuq66i6q.png" width="500px" /> </center> <p>Буду счастлив, если пользователи Селенида его посмотрят. Вы же хотите приобщиться к таинству опен-сорса?</p> <p><br /> Всем щастья! <br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2021/01/23/selenide-5.18.0/ http://ru.selenide.org/2021/01/23/selenide-5.18.0 2021-01-23T00:00:00+00:00 Вышла Selenide 5.17.2 <p>Доброе утро!<br /> Гномики всё никак не успокоятся. Завтра утром они принесут в ваши носочки последний подарочек: релиз <a href="https://github.com/selenide/selenide/milestone/110?closed=1">Selenide 5.17.2</a>.</p> <p><br /></p> <h1 id="теперь-commands-возвращают-selenideelement-вместо-webelement">Теперь <code class="language-plaintext highlighter-rouge">Commands</code> возвращают <code class="language-plaintext highlighter-rouge">SelenideElement</code> вместо <code class="language-plaintext highlighter-rouge">WebElement</code></h1> <p>Это даёт возможность <em>чейнить</em> вызовы методов <code class="language-plaintext highlighter-rouge">$.execute(Command)</code> с другими селенидовскими метода, делая ваши тесты ещё лаконичнее и экспрессивнее:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">".lupa"</span><span class="o">).</span><span class="na">execute</span><span class="o">(</span><span class="k">new</span> <span class="nc">ScrollToCenter</span><span class="o">()).</span><span class="err">$</span><span class="o">(</span><span class="s">".pupa"</span><span class="o">).</span><span class="na">click</span><span class="o">();</span> </code></pre></div></div> <p>Спасибо <a href="https://github.com/BorisOsipov">Boris Osipov</a> за <a href="https://github.com/selenide/selenide/pull/1355">PR 1355</a>.</p> <p><br /></p> <h1 id="починили-метод-setvaluenull">Починили метод <code class="language-plaintext highlighter-rouge">$.setValue(null)</code></h1> <p>См. <a href="https://github.com/selenide/selenide/issues/1356">issue 1356</a>. Спасибо <a href="https://github.com/dzem">Dmitriy Zemlyanitsyn</a> за <a href="https://github.com/selenide/selenide/pull/1357">PR 1357</a>.</p> <p><br /></p> <h1 id="включили-soft-asserts-в-методах-beforeall-и-afterall-в-junit-5">Включили soft asserts в методах @BeforeAll и @AfterAll (в JUnit 5)</h1> <p>См. <a href="https://github.com/selenide/selenide/issues/981">issue 981</a>, <a href="https://github.com/selenide/selenide/issues/1070">issue 1070</a> и <a href="https://github.com/selenide/selenide/pull/1359">PR 1359</a>.</p> <p><br /></p> <h1 id="починили-файл-selenide-5172-javadocjar">Починили файл <a href="https://search.maven.org/remotecontent?filepath=com/codeborne/selenide/5.17.2/selenide-5.17.2-javadoc.jar">selenide-5.17.2-javadoc.jar</a></h1> <p>теперь он содержит javadoc для всех классов.</p> <p><br /></p> <p><br /> Ещё раз с наступающим! <br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2020/12/30/selenide-5.17.2/ http://ru.selenide.org/2020/12/30/selenide-5.17.2 2020-12-30T00:00:00+00:00 Вышла Selenide 5.17.0 <p>Доброй ночи!</p> <p>Я трепетно отношусь к Католическому Рождеству.<br /> Потому, что именно в Рождество террористы захватили небоскрёб Накатоми, и Брюс замочил Ханса Грубера. А потом взорвал самолёт зажигалкой.</p> <p>Поэтому ловите рождественский релиз <a href="https://github.com/selenide/selenide/milestone/108?closed=1">Selenide 5.17.0</a>.</p> <p><br /></p> <h1 id="добавили-метод-asname">Добавили метод $.as(“name”)</h1> <p>Чувствую, что открываю ящик пандоры, но что уж поделаешь…</p> <p>В общем, мы добавили метод <code class="language-plaintext highlighter-rouge">as</code>, позволяющий давать элементам читаемые имена.</p> <p>Чтобы продемонстрировать эффект, давайте сравним эти две строки в тесте:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="nc">By</span><span class="o">.</span><span class="na">xpath</span><span class="o">(</span><span class="s">"/long/ugly/xpath[1][2][3]"</span><span class="o">)).</span><span class="na">shouldNot</span><span class="o">(</span><span class="n">exist</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="nc">By</span><span class="o">.</span><span class="na">xpath</span><span class="o">(</span><span class="s">"/long/ugly/xpath[1][2][3]"</span><span class="o">)).</span><span class="na">as</span><span class="o">(</span><span class="s">"Login button"</span><span class="o">).</span><span class="na">shouldNot</span><span class="o">(</span><span class="n">exist</span><span class="o">);</span> </code></pre></div></div> <p>Результат в отчёте будет таким:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> +---------------------------------------+--------------------+----------+----------+ |Element |Subject |Status |ms. | +---------------------------------------+--------------------+----------+----------+ |By.xpath: /long/ugly/xpath[1][2][3] |should not(exist) |PASS |13 | |Login button |should not(exist) |PASS |38 | +---------------------------------------+--------------------+----------+----------+ </code></pre></div></div> <p>В последней строке вместо длинного нечитабельного xpath мы видим понятное имя “Login button”.</p> <p>NB! Не торопитесь использовать эту возможность. Лично я воспринимаю её как “хак последней надежды”.<br /> В отчёте всегда лучше видеть настоящий локатор, чем кем-то придуманное имя, которое всегда может оказаться:</p> <ul> <li>Обманчивым</li> <li>Устаревшим</li> <li>Вводящим в заблуждение</li> </ul> <p>Лучше инвестируйте свои усилия в то, чтобы использовать читаемые локаторы. Ну и грамотно называть переменные и методы. Вот где сила, брат!</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1200">issue 1200</a> и <a href="https://github.com/selenide/selenide/pull/1353">PR 1353</a>.</p> <p><br /></p> <h1 id="добавили-настроек-нашему-headless-chrome">Добавили настроек нашему headless chrome</h1> <p>Мы взяли и добавили нашему безголовому хрому те же настройки, <a href="https://github.com/puppeteer/puppeteer/blob/7a2a41f2087b07e8ef1feaf3881bdcc3fd4922ca/src/Launcher.js#L261">что и в puppeteer</a>.<br /> Ребята из puppeteer же не дураки, знают, что делают. Мы как они.</p> <p>Спасибо <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> за <a href="https://github.com/selenide/selenide/pull/1329">PR 1329</a>.</p> <p>P.S. Интересно, если ребята из puppeteer решать с крыши спрыгнуть, мы тоже спрыгнем?</p> <p><br /></p> <h1 id="починили-byshadowcssfindelements">Починили <code class="language-plaintext highlighter-rouge">ByShadowCss.findElements</code></h1> <p>Оказалось, в одном хитром случае он возвращал не все элементы: когда в DOM было несколько <em>inner shadow hosts</em> (как это по-православному, бог ты мой?)</p> <p>Теперь возвращает все.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1346">issue 1346</a>. Спасибо <a href="https://github.com/dpeger">Daniel H. Peger</a> за <a href="https://github.com/selenide/selenide/pull/1347">PR 1347</a>.</p> <p><br /></p> <h1 id="добавили-метод-should-с-кастомным-таймаутом">Добавили метод $.should* с кастомным таймаутом</h1> <p>Как вы все знаете, в Селениде есть две основных группы методов:</p> <ol> <li><code class="language-plaintext highlighter-rouge">$.shouldHave</code> / <code class="language-plaintext highlighter-rouge">$.shouldBe</code> / <code class="language-plaintext highlighter-rouge">$.should</code> – используют таймаут по умолчанию</li> <li><code class="language-plaintext highlighter-rouge">$.waitUntil</code> / <code class="language-plaintext highlighter-rouge">$.waitWhile</code> – используют заданный таймаут</li> </ol> <p>Методы <code class="language-plaintext highlighter-rouge">$.wait*</code> полезны для ожидания явно долгих действий, которые точно длятся дольше обычного таймаута (который 4 секунды по умолчанию).</p> <p>Проблема с <code class="language-plaintext highlighter-rouge">$.wait*</code> методами чисто грамматическая: встроенные селенидовские проверки не звучат по-английски корректно с глаголом “wait”:</p> <ol> <li><code class="language-plaintext highlighter-rouge">element should have text</code> - звучит</li> <li><code class="language-plaintext highlighter-rouge">element wait until text</code> - не звучит</li> </ol> <p>Не смертельно, но ухо режет (как говорил Ван Гог, гы-гы).</p> <p>Поэтому теперь вы можете заменить <code class="language-plaintext highlighter-rouge">$.waitUntil(hasText("bob"), 18_000)</code> на <code class="language-plaintext highlighter-rouge">$.shouldHave(text("bob"), Duration.ofSeconds(18))</code>.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1136">issue 1136</a>, <a href="https://github.com/selenide/selenide/issues/1338">issue 1338</a> и <a href="https://github.com/selenide/selenide/pull/1340">PR 1340</a>.</p> <p><br /></p> <h1 id="пэдж-обжекты">Пэдж обжекты</h1> <p>Следующий блок улучшений касается пэдж обжектов. Как вы знаете, в селениде есть возможность объявлять свои пэдж обжекты,</p> <ul> <li>а в них объявлять поля с аннотациями <code class="language-plaintext highlighter-rouge">@FindBy</code>,</li> <li>а поля эти могут быть как стандартные селениумовские <code class="language-plaintext highlighter-rouge">WebElement</code>,</li> <li>так и наши <code class="language-plaintext highlighter-rouge">SelenideElement</code>,</li> <li>и даже переиспользуемые компоненты <code class="language-plaintext highlighter-rouge">ElementsContainer</code>, из которых можно собирать пэдж обжекты, как из кирпичиков.</li> </ul> <p>И работает всё это в лучших традициях селенида: ленивая загрузка и перезагрузка элементов, вот это всё.</p> <p><br /></p> <p>В общем, в этих <code class="language-plaintext highlighter-rouge">@FindBy</code> уже давно были шероховатости:</p> <ol> <li>не работала ленивая загрузка для полей ПО с типом <code class="language-plaintext highlighter-rouge">List&lt;ElementsContainer&gt;</code> (см. issue <a href="https://github.com/selenide/selenide/issues/282">282</a> и <a href="https://github.com/selenide/selenide/issues/482">482</a>)</li> <li>не поддерживались поля ПО с дженериками (см. <a href="https://github.com/selenide/selenide/issues/694">issue 694</a>)</li> </ol> <p>И это было сложно исправить. Пришлось погрузиться в этот (старый) код и серьёзно его порефакторить. Пришлось напрячь мозги и применить все свои остатки былого абстрактного мышления.</p> <p>Так что эти два пулреквеста - предмет моей гордости:</p> <ul> <li><a href="https://github.com/selenide/selenide/pull/1351">support page object fields of generic types</a></li> <li><a href="https://github.com/selenide/selenide/pull/1354">enable lazy loading for Page Object fields of type <code class="language-plaintext highlighter-rouge">List&lt;ElementsContainer&gt;</code></a></li> </ul> <p><br /></p> <h1 id="и-напоследок-пачка-технологических-улучшений">И напоследок пачка технологических улучшений:</h1> <ul> <li>разбили проект на подпроекты - см. <a href="https://github.com/selenide/selenide/pull/1348">PR 1348</a></li> <li>исправили тесты селенида, зависящие от ОС - См. <a href="https://github.com/selenide/selenide/issues/1344">issue 1344</a> и <a href="https://github.com/selenide/selenide/pull/1345">PR 1345</a>, спасибо <a href="https://github.com/dpeger">Daniel H. Peger</a></li> <li>подчистили код <code class="language-plaintext highlighter-rouge">Plugins</code> – спасибо <a href="https://github.com/yorlov">Yuri Orlov</a> за <a href="https://github.com/selenide/selenide/pull/1343">PR 1343</a></li> <li>Обновились до browserup-proxy:2.1.2 и guava:30.1-jre</li> <li>Добавили поддержку chrome 88, edge 89, opera 73</li> </ul> <p><br /></p> <h3 id="известные-проблемы">Известные проблемы:</h3> <ul> <li>файл <a href="https://search.maven.org/remotecontent?filepath=com/codeborne/selenide/5.17.0/selenide-5.17.0-javadoc.jar">selenide-5.17.0-javadoc.jar</a> получился неполным: он содержит javadoc не для всех классов. Надеемся, никто не обидится. Исправим в версии 5.17.1.</li> </ul> <p><br /></p> <h1 id="итоги">Итоги</h1> <p>В общем, заканчиваем год на позитивной ноте:<br /> провели серьёзный рефакторинг и исправили несколько старых болячек.<br /> В новый год мы переходим всего с одним экраном в <a href="https://github.com/selenide/selenide/issues">github issues</a> вместо прежних двух.</p> <p>И количество скачиваний селенида выросло за год с 102 до 167 тысяч.</p> <center> <img src="/images/2020/12/selenide.downloads.png" width="800" /> </center> <p><br /> С наступающим! <br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2020/12/26/selenide-5.17.0/ http://ru.selenide.org/2020/12/26/selenide-5.17.0 2020-12-26T00:00:00+00:00 Вышла Selenide 5.16.2 <p>Всем привет!</p> <p>Мы выпустили релиз <a href="https://github.com/selenide/selenide/milestone/109?closed=1">Selenide 5.16.2</a>.</p> <p>Нет, вы не подумайте, что в недавнем крупном релизе <a href="/2020/11/20/selenide-5.16.0/">Selenide 5.16.0</a> была куча багов. Вовсе нет.</p> <p>Данный релиз 5.16.2 - это исправление кучи старых мелких бажочков, просто сейчас дошли до них руки.</p> <p>Итак, коротко:</p> <h2 id="selenide-5.16.2">Релиз <a href="https://github.com/selenide/selenide/milestone/109?closed=1">5.16.2</a> (вышел 25.11.2020)</h2> <ul> <li><a href="https://github.com/selenide/selenide/issues/1332">#1332</a> return old click(int, int) command logic – thanks to Petro Ovcharenko for PR <a href="https://github.com/selenide/selenide/pull/1333">#1333</a></li> <li>make SoftAssertsExtension thread-safe – thanks to @dtuchs for PR <a href="https://github.com/selenide/selenide/pull/1334">#1334</a></li> <li><a href="https://github.com/selenide/selenide/issues/1258">#1258</a> fix soft asserts with ParameterizedTest in jUnit5 – see PR <a href="https://github.com/selenide/selenide/pull/1328">#1328</a></li> <li><a href="https://github.com/selenide/selenide/issues/1293">#1293</a> don’t report “Element not found” in case of other errors – see PR <a href="https://github.com/selenide/selenide/pull/1326">#1326</a></li> <li><a href="https://github.com/selenide/selenide/issues/1290">#1290</a> don’t show unused page object fields in report – see PR <a href="https://github.com/selenide/selenide/pull/1327">#1327</a></li> <li>upgrade to littleproxy:2.0.1 – see PR <a href="https://github.com/selenide/selenide/pull/1325">#1325</a></li> </ul> <h2 id="selenide-5.16.1">Релиз <a href="https://github.com/selenide/selenide/milestone/106?closed=1">5.16.1</a> (вышел 23.11.2020)</h2> <p>Тут было два исправления, чтобы хром можно было запускать с расширениями.</p> <ul> <li><a href="https://github.com/selenide/selenide/issues/1314">#1314</a> do not exclude “load-extension” switch if Chrome is opened with extensions – see PR <a href="https://github.com/selenide/selenide/pull/1324">#1324</a></li> <li><a href="https://github.com/selenide/selenide/issues/1315">#1315</a> support custom DriverFactory for running remote browsers – see PR <a href="https://github.com/selenide/selenide/pull/1324">#1324</a></li> </ul> <h2 id="news">Новости</h2> <p>Раз осталось место, поделюсь новенькими ссылками:</p> <ul> <li>Пример от LambdaTest: <a href="https://github.com/LambdaTest/selenide-testng-sample">selenide-testng-sample</a></li> <li>Видосик про Селенид на португальском: <a href="https://www.youtube.com/watch?v=yOfrqZUsFuU&amp;feature=youtu.be&amp;ab_channel=BluesoftLabs">Testes de Aceitação em Java com Selenide, Adriano Magalhães</a></li> <li>Курс по Селениду где-то в Бразилии: <a href="https://inoveteste.com.br/automacao-web-descomplicada-com-selenide/">Automação Web Descomplicada Com Selenide</a></li> <li>Визуальное тестирование: <a href="https://medium.com/automated-visual-testing-with-applitools/getting-started-with-the-applitools-sdk-653f2cd1ad48">Applitools+Selenide</a></li> <li>Пример проекта: <a href="https://github.com/bmurmistro/applitools">Getting started with applitools</a></li> </ul> <p><br /></p> <p>Selenide 5.17.0 уже не за горами, не переключайтесь!</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2020/11/25/selenide-5.16.2/ http://ru.selenide.org/2020/11/25/selenide-5.16.2 2020-11-25T00:00:00+00:00 Вышла Selenide 5.16.0 <p>Всем привет!</p> <p>Мы выпустили релиз <a href="https://github.com/selenide/selenide/milestone/105?closed=1">Selenide 5.16.0</a>.</p> <h2 id="плагины">Плагины</h2> <p>В начале 2020 года на конференции <a href="https://seleniumcamp.com/materials/">SeleniumCamp</a> я рассказывал про <a href="https://seleniumcamp.com/talk/bof-glorious-past-and-promising-future-of-selenide/">roadmap селенида</a>. Одна из ключевых идей на этот год была создать в селениде возможность подключать сторонние плагины.</p> <p><strong>И вот этот день настал!</strong></p> <p>На данный момент доступно два плагина:</p> <ul> <li><a href="https://github.com/selenide/selenide-appium">selenide-appium 1.5.0</a></li> <li><a href="https://github.com/selenide/selenide-selenoid">selenide-selenoid 1.0.0</a></li> </ul> <p>Расскажем о них в отдельных постах.</p> <p>Вероятно, дальше стоит оформить в виде плагинов поддержку Allure, JUnit, TestNG, AShot.<br /> <em>Накидывайте ещё идеи!</em></p> <p>См. <a href="https://github.com/selenide/selenide/issues/1051">issue #1051</a> и <a href="https://github.com/selenide/selenide/pull/1264">PR #1264</a>, <a href="https://github.com/selenide/selenide/pull/1317">PR 1317</a> и <a href="https://github.com/selenide/selenide/pull/1321">PR 1321</a>.</p> <h2 id="сообщения-об-ошибках">Сообщения об ошибках</h2> <p>Одна из основных обязанностей селенида - составлять подробные сообщения об ошибках в случае падения тестов.<br /> Иногда в эти сообщения тоже закрадываются неточности в каких-то сложных случаях.<br /> В этом релизе мы запилили целую пачку улучшений сообщений об ошибках:</p> <h3 id="улучшили-описание-проверок-and-и-not">Улучшили описание проверок AND и NOT</h3> <p>Нормальный способ устроить негативную проверку в селениде - метод <code class="language-plaintext highlighter-rouge">shouldNotHave</code>. А проверить несколько условий подряд - просто через запятую:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"#username"</span><span class="o">).</span><span class="na">shouldNotHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"admin"</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">"#username"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"____"</span><span class="o">),</span> <span class="n">attribute</span><span class="o">(</span><span class="s">"data-masked"</span><span class="o">));</span> </code></pre></div></div> <p>Но есть ещё методы <code class="language-plaintext highlighter-rouge">Condition.not</code> и <code class="language-plaintext highlighter-rouge">Condition.and</code> для особых случаев: например, с их помощью можно определять составные условия, таким образом составляя целый DSL для ваших тестов.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">public</span> <span class="kd">class</span> <span class="nc">MyConditions</span> <span class="o">{</span> <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">Condition</span> <span class="no">NONADMIN</span> <span class="o">=</span> <span class="n">not</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"admin"</span><span class="o">));</span> <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">Condition</span> <span class="no">MASKED</span> <span class="o">=</span> <span class="n">and</span><span class="o">(</span><span class="s">"MASKED"</span><span class="o">,</span> <span class="n">text</span><span class="o">(</span><span class="s">"___"</span><span class="o">),</span> <span class="n">attribute</span><span class="o">(</span><span class="s">"data-masked"</span><span class="o">));</span> <span class="o">}</span> <span class="kd">public</span> <span class="kd">class</span> <span class="nc">MyTest</span> <span class="o">{</span> <span class="err">$</span><span class="o">(</span><span class="s">"#username"</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="no">MASKED</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#username"</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="no">NONADMIN</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>Оказалось, что оба эти методы выводили в отчёте неполную информацию:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="o">|</span> <span class="err">#</span><span class="n">username</span> <span class="o">|</span><span class="n">should</span> <span class="nf">be</span><span class="o">(</span><span class="no">MASKED</span><span class="o">)</span> <span class="o">|</span><span class="no">PASS</span> <span class="o">|</span> <span class="o">|</span> <span class="err">#</span><span class="n">username</span> <span class="o">|</span><span class="n">should</span> <span class="nf">have</span><span class="o">(</span><span class="n">not</span> <span class="n">text</span><span class="o">)</span> <span class="o">|</span><span class="no">PASS</span> <span class="o">|</span> </code></pre></div></div> <p>Проблема в том, что в нём не виден ожидаемый текст (“admin”) и другие условия.</p> <p>Теперь мы эту проблему исправили, и при падении проверки вы увидите сообщение с текстом:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="o">|</span> <span class="err">#</span><span class="n">username</span> <span class="o">|</span><span class="n">should</span> <span class="nf">be</span><span class="o">(</span><span class="nl">MASKED:</span> <span class="n">text</span> <span class="err">'</span><span class="n">___</span><span class="err">'</span> <span class="n">and</span> <span class="n">attribute</span> <span class="n">data</span><span class="o">-</span><span class="n">masked</span><span class="o">)</span> <span class="o">|</span><span class="no">PASS</span> <span class="o">|</span> <span class="o">|</span> <span class="err">#</span><span class="n">username</span> <span class="o">|</span><span class="n">should</span> <span class="nf">have</span><span class="o">(</span><span class="n">not</span> <span class="n">text</span> <span class="err">'</span><span class="n">admin</span><span class="err">'</span><span class="o">)</span> <span class="o">|</span><span class="no">PASS</span> <span class="o">|</span> </code></pre></div></div> <p>Спасибо <a href="https://github.com/fokinp">Pavel Fokin</a> за <a href="https://github.com/selenide/selenide/pull/1306">PR 1306</a> и <a href="https://github.com/selenide/selenide/pull/1300">PR 1306</a>.</p> <p><br /></p> <h3 id="добавили-информацию-о-предках">Добавили информацию о предках</h3> <p>Селенид позволяет искать элементы внутри других элементов. Например, так:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"#user-table"</span><span class="o">).</span><span class="err">$</span><span class="o">(</span><span class="s">"thead"</span><span class="o">).</span><span class="err">$</span><span class="o">(</span><span class="s">"trrrr-chah-chah"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Age"</span><span class="o">));</span> </code></pre></div></div> <p>Но если такая проверка падает, в сообщении был виден только локатор дочернего элемента:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">Element</span> <span class="n">not</span> <span class="n">found</span> <span class="o">{</span><span class="n">trrrr</span><span class="o">-</span><span class="n">chah</span><span class="o">-</span><span class="n">chah</span><span class="o">}</span> </code></pre></div></div> <p>А теперь мы также добавили информацию и о родителях:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">Element</span> <span class="n">not</span> <span class="n">found</span> <span class="o">{</span><span class="err">#</span><span class="n">user</span><span class="o">-</span><span class="n">table</span><span class="o">/</span><span class="n">thead</span><span class="o">/</span><span class="n">trrrr</span><span class="o">-</span><span class="n">chah</span><span class="o">-</span><span class="n">chah</span><span class="o">}</span> </code></pre></div></div> <p>Спасибо <a href="https://github.com/petroOv-PDFfiller">Petro Ovcharenko</a> за <a href="https://github.com/selenide/selenide/pull/1312">PR 1312</a>.</p> <p><br /> <br /></p> <h3 id="добавили-актуальные-текст-для-проверок-owntext-и-exactowntext">Добавили актуальные текст для проверок <code class="language-plaintext highlighter-rouge">ownText</code> и <code class="language-plaintext highlighter-rouge">exactOwnText</code></h3> <p>Как вы помните, в Selenide 5.15.0 мы добавили проверки <code class="language-plaintext highlighter-rouge">ownText</code> и <code class="language-plaintext highlighter-rouge">exactOwnText</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"#child_div1"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">ownText</span><span class="o">(</span><span class="s">"Sonar"</span><span class="o">));</span> </code></pre></div></div> <p>Но и тут оказалось, что при падении такой проверки в сообщении не выводился, а какой же “свой текст” был на самом деле. Выводился только текст элемента с детьми:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">Element</span> <span class="n">should</span> <span class="n">have</span> <span class="n">own</span> <span class="n">text</span> <span class="err">'</span><span class="nc">Sonar</span><span class="err">'</span> <span class="o">{</span><span class="err">#</span><span class="n">child_div1</span><span class="o">}</span> <span class="nl">Element:</span> <span class="err">'</span><span class="o">&lt;</span><span class="n">div</span> <span class="n">id</span><span class="o">=</span><span class="s">"child_div1"</span><span class="o">&gt;</span><span class="nc">Son</span><span class="o">&lt;/</span><span class="n">div</span><span class="o">&gt;</span><span class="err">'</span> </code></pre></div></div> <p>Теперь мы добавили строчку “Actual value” с собственным текстом элемента:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">Element</span> <span class="n">should</span> <span class="n">have</span> <span class="n">own</span> <span class="n">text</span> <span class="err">'</span><span class="nc">Sonar</span><span class="err">'</span> <span class="o">{</span><span class="err">#</span><span class="n">child_div1</span><span class="o">}</span> <span class="nl">Element:</span> <span class="err">'</span><span class="o">&lt;</span><span class="n">div</span> <span class="n">id</span><span class="o">=</span><span class="s">"child_div1"</span><span class="o">&gt;</span><span class="nc">Son</span><span class="o">&lt;/</span><span class="n">div</span><span class="o">&gt;</span><span class="err">'</span> <span class="nc">Actual</span> <span class="nl">value:</span> <span class="nc">Son</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1261">issue 1261</a> и <a href="https://github.com/selenide/selenide/pull/1294">PR 1294</a>.</p> <p><br /> <br /></p> <h3 id="кидаем-правильную-ошибку-при-загрузке-несуществующего-файла">Кидаем правильную ошибку при загрузке несуществующего файла</h3> <p>Если вы пытались загрузить несуществующий файл:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"input[type='file']"</span><span class="o">).</span><span class="na">uploadFile</span><span class="o">(</span><span class="k">new</span> <span class="nc">File</span><span class="o">(</span><span class="s">"/foo/bar/xyz.pdf"</span><span class="o">));</span> </code></pre></div></div> <p>То получали некорректную ошибку:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">Element</span> <span class="n">not</span> <span class="n">found</span> <span class="o">{</span><span class="n">input</span><span class="o">[</span><span class="n">type</span><span class="o">=</span><span class="err">'</span><span class="n">file</span><span class="err">'</span><span class="o">]}</span> <span class="o">...</span> <span class="nc">Caused</span> <span class="nl">by:</span> <span class="nl">InvalidArgumentException:</span> <span class="n">invalid</span> <span class="nl">argument:</span> <span class="nc">File</span> <span class="n">not</span> <span class="n">found</span> <span class="o">:</span> <span class="o">/</span><span class="n">foo</span><span class="o">/</span><span class="n">bar</span><span class="o">/</span><span class="n">xyz</span><span class="o">.</span><span class="na">pdf</span> </code></pre></div></div> <p>Казалось бы, мелочь, но иногда это сбивало с толку.</p> <p>Теперь мы это исправили, и вы получите сразу</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nl">InvalidArgumentException:</span> <span class="n">invalid</span> <span class="nl">argument:</span> <span class="nc">File</span> <span class="n">not</span> <span class="n">found</span> <span class="o">:</span> <span class="o">/</span><span class="n">foo</span><span class="o">/</span><span class="n">bar</span><span class="o">/</span><span class="n">xyz</span><span class="o">.</span><span class="na">pdf</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/987">issue 987</a> и <a href="https://github.com/selenide/selenide/pull/1301">PR 1301</a>.</p> <p><br /></p> <blockquote> <p>Корень проблемы в том, что в селенум не хватает отдельных классов ошибок для всех возможных нестандартных ситуаций, и простой <code class="language-plaintext highlighter-rouge">WebDriverException</code> может говорить как о ненайденном элементе, так и неверной кодировке в вводимой строке. См., например, <a href="https://github.com/selenide/selenide/issues/1293">issues 1293</a>.</p> <p>Плюс некоторые реализации вебдрайвера могут кидать какие-то нелогичные ошибки - например, IEDriver когда-то кидал <code class="language-plaintext highlighter-rouge">Throwable</code> вместо <code class="language-plaintext highlighter-rouge">ElementNotFound</code>.</p> <p>Поэтому в своё время в селениде была принята консервативная стратегия: если не удалось определить тип ошибки точнее, по умолчанию считаем, что элемент не найден. А в “caused by” будут видны подробности.</p> </blockquote> <p><br /> <br /></p> <h3 id="адекватно-показываем-clickoptions-в-отчёте">Адекватно показываем ClickOptions в отчёте</h3> <p>Как вы помните, в Selenide 5.15.0 мы добавили удобные методы для клика со всевозможными опциями:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"#page"</span><span class="o">).</span><span class="na">click</span><span class="o">(</span><span class="n">usingJavaScript</span><span class="o">().</span><span class="na">offset</span><span class="o">(</span><span class="mi">123</span><span class="o">,</span> <span class="mi">222</span><span class="o">));</span> </code></pre></div></div> <p>И снова оказалось, что в отчёте такая строка выглядит некрасиво:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="o">|</span> <span class="err">#</span><span class="n">page</span> <span class="o">|</span><span class="n">click</span><span class="o">(</span><span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">ClickOptions</span><span class="err">@</span><span class="mi">33617539</span><span class="o">)</span> <span class="o">|</span><span class="no">PASS</span> <span class="o">|</span> </code></pre></div></div> <p>Мы и это исправили, теперь строчка стала <em>окейнее</em>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="o">|</span> <span class="err">#</span><span class="n">page</span> <span class="o">|</span><span class="n">click</span><span class="o">(</span><span class="nl">method:</span> <span class="no">JS</span><span class="o">,</span> <span class="nl">offsetX:</span> <span class="mi">123</span><span class="o">,</span> <span class="nl">offsetY:</span> <span class="mi">222</span><span class="o">)</span> <span class="o">|</span><span class="no">PASS</span> <span class="o">|</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1302">issue 1302</a> и <a href="https://github.com/selenide/selenide/pull/1303">PR 1303</a>.</p> <p><br /></p> <h2 id="другое">Другое</h2> <h3 id="добавили-проверку-shouldhaveexacttextscasesensitiveinanyorder">Добавили проверку <code class="language-plaintext highlighter-rouge">$$.shouldHave(exactTextsCaseSensitiveInAnyOrder(...))</code></h3> <p>В селениде уже давно есть проверки для коллекций:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$$</span><span class="o">(</span><span class="s">".employee"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">texts</span><span class="o">(</span><span class="s">"вася"</span><span class="o">,</span> <span class="s">"петя"</span><span class="o">,</span> <span class="s">"катя"</span><span class="o">));</span> <span class="c1">// case-insensitive, substring</span> <span class="err">$$</span><span class="o">(</span><span class="s">".employee"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">textsInAnyOrder</span><span class="o">(</span><span class="s">"вася"</span><span class="o">,</span> <span class="s">"катя"</span><span class="o">,</span> <span class="s">"петя"</span><span class="o">));</span> <span class="c1">// case-insensitive, substring, any order</span> <span class="err">$$</span><span class="o">(</span><span class="s">".employee"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">exactTexts</span><span class="o">(</span><span class="s">"вася"</span><span class="o">,</span> <span class="s">"петя"</span><span class="o">,</span> <span class="s">"катя"</span><span class="o">));</span> <span class="c1">// case-insensitive, full string match</span> </code></pre></div></div> <p>И теперь к ним добавилась ещё одна - менее толерантная:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="c1">// case-sensitive, full string match, any order</span> <span class="err">$$</span><span class="o">(</span><span class="s">".employee"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">exactTextsCaseSensitiveInAnyOrder</span><span class="o">(</span><span class="s">"Вася"</span><span class="o">,</span> <span class="s">"Петя"</span><span class="o">,</span> <span class="s">"Катя"</span><span class="o">));</span> </code></pre></div></div> <p>Спасибо <a href="https://github.com/plagov">Vitali Plagov</a> за <a href="https://github.com/selenide/selenide/pull/1286">PR 1286</a>.</p> <p><br /></p> <h3 id="исправили-проверку-href-со-спецсимволами">Исправили проверку <code class="language-plaintext highlighter-rouge">href</code> со спец.символами</h3> <p>Как вы помните, в Selenide 5.15.0 мы добавили проверку <code class="language-plaintext highlighter-rouge">href</code>.<br /> Оказалось, что она неправильно работала, если в <code class="language-plaintext highlighter-rouge">href</code> затесались экранированные символы, как во второй строке:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"a"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">href</span><span class="o">(</span><span class="s">"/foo/bar/details.html"</span><span class="o">));</span> <span class="c1">// works</span> <span class="err">$</span><span class="o">(</span><span class="s">"a"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">href</span><span class="o">(</span><span class="s">"/files/some%20file.pdf"</span><span class="o">));</span> <span class="c1">// fails</span> </code></pre></div></div> <p>Проблема исправлена.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1298">issue 1298</a>.<br /> Спасибо <a href="https://github.com/rerednaw">rerednaw</a> за <a href="https://github.com/selenide/selenide/pull/1299">PR 1299</a>.</p> <p><br /></p> <h3 id="разрешаем-хрому-скачивать-несколько-файлов">Разрешаем хрому скачивать несколько файлов</h3> <p>Бывают такие хитрые ссылки, по клику на которые браузер начинает скачивать не один, а сразу два или больше файлов.<br /> Оказалось, что в этом случае браузер Chrome показывает диалог “Уверены, что хотите скачать все файлы?” - и этот диалог не даёт ничего дальше сделать, пока пользователь не нажмёт кнопку. И ваш тест падает.</p> <blockquote> <p>Самое противное в этой проблеме то, что её очень сложно повторить руками: браузер показывает диалог только в первый раз, так что при локальном запуске скорее всего вы его не увидите, и тест будет зелёным.</p> </blockquote> <p>Чтобы вылечить эту проблему, мы добавили при запуске хрома специальный ключик <code class="language-plaintext highlighter-rouge">profile.default_content_setting_values.automatic_downloads=1</code>, который сразу разрешает хрому качать сколько угодно файлов без всяких диалогов.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1307">issue 1307</a>.<br /> Спасибо <a href="https://github.com/vinogradoff">Alexei Vinogradov</a> за <a href="https://github.com/selenide/selenide/pull/1308">PR 1308</a>.</p> <p><br /></p> <h3 id="разрешили-скачивать-файлы-со-слэшем-в-названии">Разрешили скачивать файлы со слэшем в названии</h3> <p>Метод <code class="language-plaintext highlighter-rouge">download</code> не разрешает скачивать файл, если в его названии есть неразрешённые символы, в числе которых был и слэш:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">File</span> <span class="n">report</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#report"</span><span class="o">).</span><span class="na">download</span><span class="o">();</span> <span class="o">--&gt;</span> <span class="nc">IllegalArgumentException</span><span class="o">(</span><span class="s">"File name cannot contain slash: 11/08/2020_-_day_transactions.pdf"</span><span class="o">)</span> </code></pre></div></div> <p>Нам казалось это логичным, ведь такие файлы тупо не разрешает создавать файловая система.<br /> Но оказалось, что иногда слэш вполне логичен - например, как разделитель в датах. И хром вполне скачивает такие файлы, просто заменяя слэш на подчёркивание.</p> <p>Теперь и селенид так делает.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1322">issue 1322</a> и <a href="https://github.com/selenide/selenide/pull/1323">PR 1323</a>.</p> <p><br /></p> <h3 id="зафиксировали-версию-guava-300-jre">Зафиксировали версию Guava 30.0-jre</h3> <p>Ох уж эта гуава!</p> <p>В коде самого селенида Guava не используется, нам она не нужна.<br /> Но с ней вечные проблемы: от неё зависят многие другие библиотеки (Selenium, LittleProxy, BrowserUpProxy, Checkstyle), и все от разных версий. А ещё ведь у неё есть специальная версия для android…</p> <p>В общем, слишком часто так случалось, что Maven или Gradle подтягивал не ту версию Guava, и селенид в итоге не работал. <br /> Нам это надоело, и теперь в селениде явно прописана свежая версия Guava <code class="language-plaintext highlighter-rouge">30.0-jre</code>. Надеемся, это поможет избежать всех этих бесконечных конфликтов завиимостей.</p> <p><br /></p> <h3 id="перешли-на-github-actions">Перешли на Github Actions</h3> <p>Как в любом приличном проекте, в Selenide есть свой набор автотестов (юнит- и интеграционных), и они запускаются автоматически для всех веток на CI сервере. Раньше мы использовали Travis CI, который предоставляет бесплатный сервис для опен-сорс проектов. Спасибо им большое за годы совместной работы. :)</p> <p>Но в этом году гитхаб выкатил свой CI сервис под названием “Github actions”.</p> <blockquote> <p>Смотри обзор от Артём Ерошенко и Севы Брекелова в <a href="http://www.youtube.com/watch?v=dxGGZQiuD6Q&amp;t=60m10s">выпуске №3 Шоу “Ошибка выжившего”</a>.</p> </blockquote> <p>И казалось логичным использовать его.</p> <p>Ура, этот день настал! Теперь все билды селенида видны <a href="https://github.com/selenide/selenide/actions">прямо на гитхабе</a>.</p> <p>Спасибо <a href="https://github.com/BorisOsipov">Boris Osipov</a> за <a href="https://github.com/selenide/selenide/pull/1319">PR 1319</a>.</p> <p><br /></p> <h2 id="уффф">Уффф.</h2> <p>Многабукаф, но вы осилили. Все молодцы!</p> <p>Как обычно - обновляйтесь, пробуйте, смело сообщайте о проблемах и делитесь идеями.</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2020/11/20/selenide-5.16.0/ http://ru.selenide.org/2020/11/20/selenide-5.16.0 2020-11-20T00:00:00+00:00 Почему прокси не работает в Selenoid? <p>Всем привет!</p> <p>Сегодня мы наконец-то раскроем тайну, почему у многих не работает прокси в Selenoid.</p> <h3 id="задача-скачать-файл">Задача: скачать файл</h3> <ul> <li>Мы запускаем тесты, в которых браузер бежит в контейнере Selenoid (обычно также и на Selenide, но необязательно).</li> <li>В ходе теста мы хотим скачать файл.</li> <li>Метод по умолчанию <code class="language-plaintext highlighter-rouge">$.download()</code> не подходит (например, потому, что скачивание происходит не по прямой ссылке).</li> <li>Поэтому мы хотим <a href="/2019/12/10/advent-calendar-download-files/">скачать файл через прокси</a>.</li> </ul> <h3 id="наши-действия">Наши действия</h3> <ol> <li>Создаём проект</li> <li>Добавляем в проект зависимость BrowserUpProxy, как указано в документации Selenide: <div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">dependencies</span> <span class="p">{</span> <span class="nf">testRuntimeOnly</span><span class="p">(</span><span class="s">"com.browserup:browserup-proxy-core:2.1.1"</span><span class="p">)</span> <span class="p">}</span> </code></pre></div> </div> </li> <li>Копипастим типичный бойлерплейт для запуска браузера в Selenoid: <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Configuration</span><span class="o">.</span><span class="na">proxyHost</span> <span class="o">=</span> <span class="s">"192.168.0.10"</span><span class="o">;</span> <span class="nc">Configuration</span><span class="o">.</span><span class="na">remote</span> <span class="o">=</span> <span class="s">"http://localhost:4444/wd/hub"</span><span class="o">;</span> <span class="nc">DesiredCapabilities</span> <span class="n">capabilities</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">DesiredCapabilities</span><span class="o">();</span> <span class="n">capabilities</span><span class="o">.</span><span class="na">setBrowserName</span><span class="o">(</span><span class="s">"chrome"</span><span class="o">);</span> <span class="n">capabilities</span><span class="o">.</span><span class="na">setVersion</span><span class="o">(</span><span class="s">"85.0"</span><span class="o">);</span> <span class="n">capabilities</span><span class="o">.</span><span class="na">setCapability</span><span class="o">(</span><span class="s">"enableVNC"</span><span class="o">,</span> <span class="kc">true</span><span class="o">);</span> <span class="n">capabilities</span><span class="o">.</span><span class="na">setCapability</span><span class="o">(</span><span class="s">"enableVideo"</span><span class="o">,</span> <span class="kc">true</span><span class="o">);</span> <span class="n">capabilities</span><span class="o">.</span><span class="na">setCapability</span><span class="o">(</span><span class="s">"enableLog"</span><span class="o">,</span> <span class="kc">true</span><span class="o">);</span> <span class="nc">Configuration</span><span class="o">.</span><span class="na">browserCapabilities</span> <span class="o">=</span> <span class="n">capabilities</span><span class="o">;</span> <span class="nc">Configuration</span><span class="o">.</span><span class="na">fileDownload</span> <span class="o">=</span> <span class="nc">FileDownloadMode</span><span class="o">.</span><span class="na">PROXY</span><span class="o">;</span> <span class="nc">Configuration</span><span class="o">.</span><span class="na">proxyEnabled</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span> </code></pre></div> </div> </li> <li>Ну и пишем тест, что-то вроде <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">open</span><span class="o">(</span><span class="s">"https://the-internet.herokuapp.com/download"</span><span class="o">);</span> <span class="nc">File</span> <span class="n">file</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="n">byText</span><span class="o">(</span><span class="s">"some-file.txt"</span><span class="o">)).</span><span class="na">download</span><span class="o">();</span> <span class="n">assertThat</span><span class="o">(</span><span class="n">file</span><span class="o">.</span><span class="na">getName</span><span class="o">()).</span><span class="na">isEqualTo</span><span class="o">(</span><span class="s">"some-file.txt"</span><span class="o">);</span> </code></pre></div> </div> </li> </ol> <h3 id="проблема">Проблема</h3> <p>И получаем ошибку при открытии браузера:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">org</span><span class="o">.</span><span class="na">openqa</span><span class="o">.</span><span class="na">selenium</span><span class="o">.</span><span class="na">WebDriverException</span><span class="o">:</span> <span class="n">unknown</span> <span class="nl">error:</span> <span class="nl">net:</span><span class="o">:</span><span class="no">ERR_TUNNEL_CONNECTION_FAILED</span> <span class="o">...</span> <span class="n">at</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">Selenide</span><span class="o">.</span><span class="na">open</span><span class="o">(</span><span class="nc">Selenide</span><span class="o">.</span><span class="na">java</span><span class="o">:</span><span class="mi">49</span><span class="o">)</span> <span class="n">at</span> <span class="n">org</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">selenoid</span><span class="o">.</span><span class="na">FileDownloadTest</span><span class="o">.</span><span class="na">download</span><span class="o">(</span><span class="nc">FileDownloadTest</span><span class="o">.</span><span class="na">java</span><span class="o">:</span><span class="mi">45</span><span class="o">)</span> </code></pre></div></div> <p><br /></p> <h3 id="ааа-паника">ААА, паника!</h3> <p>На этом месте большинство людей паникует, перебирает кучу опций браузера и селенидовских настроек и в конце концов пишет в чатик автоматизаторов.</p> <p>А ведь всего-то надо было почитать внимательно лог.<br /> В логе чётко видна проблема:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span><span class="nc">LittleProxy</span><span class="o">-</span><span class="mi">0</span><span class="o">-</span><span class="nc">ProxyToServerWorker</span><span class="o">-</span><span class="mi">1</span><span class="o">]</span> <span class="no">ERROR</span> <span class="n">org</span><span class="o">.</span><span class="na">littleshoot</span><span class="o">.</span><span class="na">proxy</span><span class="o">.</span><span class="na">impl</span><span class="o">.</span><span class="na">ProxyToServerConnection</span> <span class="o">-</span> <span class="o">(</span><span class="no">HANDSHAKING</span><span class="o">)</span> <span class="o">[</span><span class="nl">id:</span> <span class="mh">0xc05a41d5</span><span class="o">,</span> <span class="nl">L:</span><span class="o">/</span><span class="mf">10.10</span><span class="o">.</span><span class="mf">10.145</span><span class="o">:</span><span class="mi">56103</span> <span class="o">-</span> <span class="nl">R:</span><span class="n">the</span><span class="o">-</span><span class="n">internet</span><span class="o">.</span><span class="na">herokuapp</span><span class="o">.</span><span class="na">com</span><span class="o">/</span><span class="mf">52.1</span><span class="o">.</span><span class="mf">16.137</span><span class="o">:</span><span class="mi">443</span><span class="o">]</span> <span class="o">:</span> <span class="nc">Caught</span> <span class="n">an</span> <span class="n">exception</span> <span class="n">on</span> <span class="nc">ProxyToServerConnection</span> <span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">NoSuchMethodError</span><span class="o">:</span> <span class="err">'</span><span class="kt">int</span> <span class="n">io</span><span class="o">.</span><span class="na">netty</span><span class="o">.</span><span class="na">buffer</span><span class="o">.</span><span class="na">ByteBuf</span><span class="o">.</span><span class="na">maxFastWritableBytes</span><span class="o">()</span><span class="err">'</span> <span class="n">at</span> <span class="n">io</span><span class="o">.</span><span class="na">netty</span><span class="o">.</span><span class="na">handler</span><span class="o">.</span><span class="na">codec</span><span class="o">.</span><span class="na">ByteToMessageDecoder</span><span class="err">$</span><span class="mi">1</span><span class="o">.</span><span class="na">cumulate</span><span class="o">(</span><span class="nc">ByteToMessageDecoder</span><span class="o">.</span><span class="na">java</span><span class="o">:</span><span class="mi">86</span><span class="o">)</span> </code></pre></div></div> <h3 id="крутим-зависимости">Крутим зависимости</h3> <p>Ошибка <code class="language-plaintext highlighter-rouge">NoSuchMethodError</code> недвусмысленно намекает на то, что у нас проблема с зависимостями: в classpath оказались какие-то два JAR’а с несовместимыми версиями.</p> <p>Против этого уже давно придумали прививку. Удивляюсь, почему так много людей до сих пор не в курсе.</p> <p>Запускаем команду:</p> <ul> <li><code class="language-plaintext highlighter-rouge">gradle dependencies</code>, или</li> <li><code class="language-plaintext highlighter-rouge">mvn dependency:tree</code></li> </ul> <p>И вуаля! - чётко видим, какие у нас JAR’ы и каких версий. Ищем там что-то похожее на “netty”.</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>\--- com.browserup:browserup-proxy-core:2.1.1 +--- io.netty:netty-codec:4.1.44.Final +--- xyz.rogfam:littleproxy:2.0.0-beta-5 | +--- io.netty:netty-all:4.1.34.Final </code></pre></div></div> <p>Как видим, у нас есть два джарника с разными версиями: <code class="language-plaintext highlighter-rouge">netty-codec:4.1.44.Final</code> и <code class="language-plaintext highlighter-rouge">netty-all:4.1.34.Final</code>.</p> <h3 id="лечим-зависимости">Лечим зависимости</h3> <p>Чтобы исправить проблему, достаточно явно прописать в <code class="language-plaintext highlighter-rouge">build.gradle</code> или <code class="language-plaintext highlighter-rouge">pom.xml</code> более новую версию <code class="language-plaintext highlighter-rouge">Netty</code>:</p> <div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">testRuntimeOnly</span><span class="p">(</span><span class="s">"io.netty:netty-all:4.1.54.Final"</span><span class="p">)</span> <span class="nf">testRuntimeOnly</span><span class="p">(</span><span class="s">"io.netty:netty-codec:4.1.54.Final"</span><span class="p">)</span> </code></pre></div></div> <p>(на самом деле достаточно только одной из этих строк. <em>Домашнее задание: какой и почему?</em>)</p> <p>Команда <code class="language-plaintext highlighter-rouge">gradle dependencies</code> показывает, что теперь версии совпадают:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>\--- com.browserup:browserup-proxy-core:2.1.1 +--- io.netty:netty-codec:4.1.44.Final -&gt; 4.1.54.Final +--- xyz.rogfam:littleproxy:2.0.0-beta-5 | +--- io.netty:netty-all:4.1.34.Final -&gt; 4.1.54.Final </code></pre></div></div> <p>Тест запускается, прокси работает, файл скачивается. Всем щастье.</p> <h3 id="мораль">Мораль</h3> <p>Будьте внимательнее к логам, братьям нашим меньшим!</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2020/11/17/why-proxy-does-not-work-in-selenoid/ http://ru.selenide.org/2020/11/17/why-proxy-does-not-work-in-selenoid 2020-11-17T00:00:00+00:00 Вышла Selenide 5.15.0 <p>Всем привет!</p> <p>Мы выпустили релиз <a href="https://github.com/selenide/selenide/milestone/104?closed=1">Selenide 5.15.0</a>.</p> <h2 id="добавили-настройку-configurationpageloadtimeout--по-умолчанию-30-секунд">Добавили настройку <code class="language-plaintext highlighter-rouge">Configuration.pageLoadTimeout</code> <br /> (по умолчанию 30 секунд)</h2> <p>Бывает так, что вебдрайвер надолго подвисает, пытаясь загрузить какую-то страницу, либо картинку на этой странице, или ещё какой-то элемент. Теряется время, сессия обрывается по таймауту и т.д.</p> <p>В этом случае хорошо бы прервать тест пораньше, но таймаут для загрузки страницы в Selenium по умолчанию слишком большой: 5 минут.</p> <p>Поэтому мы добавили в Selenide настройку <code class="language-plaintext highlighter-rouge">Configuration.pageLoadTimeout</code>, чтобы этот таймаут было легко менять.</p> <p>Внимание! Значение по умолчанию - 30 секунд. Если ваши тесты начали падать по таймауту - знайте, какую настройку подкрутить.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1268">issue 1268</a> и <a href="https://github.com/selenide/selenide/pull/1269">PR 1269</a>.</p> <h2 id="добавили-универсальный-метод-клика-с-параметром-clickoptions">Добавили универсальный метод клика<br /> с параметром <code class="language-plaintext highlighter-rouge">ClickOptions</code></h2> <p>В некотором роде это новое слово в API селенида.</p> <p>В селениде изначально был метод <code class="language-plaintext highlighter-rouge">$.click()</code>, который просто вызывал обычный селениумовский метод <code class="language-plaintext highlighter-rouge">WebElement.click()</code>. Который кликает (вроде как) в центр элемента.</p> <p>Со временем начали появляться вариации:</p> <ul> <li>Настройка <code class="language-plaintext highlighter-rouge">Configuration.clickViaJs</code>, чтобы кликать не вызовом <code class="language-plaintext highlighter-rouge">WebElement.click()</code>, а через JavaScript. Теоретически это должно сделать тесты стабильнее (а может, и быстрее) и позволит кликать то, что обычно не получается.</li> <li>Клик со сдвигом <code class="language-plaintext highlighter-rouge">$.click(offsetX, offsetY)</code>, чтобы кликать не в центр элемента</li> </ul> <p>Неудобно в этом то, что невозможно кликать то через JS, то через селениум - настройка глобальная. Пришлось бы её постоянно менять.</p> <p>Поэтому мы добавили метод, в который можно явно передавать парметр - способ клика.</p> <p>Теперь кликать можно без изменения глобальной настройки, хоть обкликайся:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"#page"</span><span class="o">).</span><span class="na">click</span><span class="o">(</span><span class="n">usingJavaScript</span><span class="o">());</span> <span class="err">$</span><span class="o">(</span><span class="s">"#page"</span><span class="o">).</span><span class="na">click</span><span class="o">(</span><span class="n">usingJavaScript</span><span class="o">().</span><span class="na">offset</span><span class="o">(</span><span class="mi">123</span><span class="o">,</span> <span class="mi">222</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">"#page"</span><span class="o">).</span><span class="na">click</span><span class="o">(</span><span class="n">usingJavaScript</span><span class="o">().</span><span class="na">offsetY</span><span class="o">(</span><span class="mi">222</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">"#page"</span><span class="o">).</span><span class="na">click</span><span class="o">(</span><span class="n">usingDefaultMethod</span><span class="o">());</span> </code></pre></div></div> <p>NB! Мы рекомендуем выставить настройку <code class="language-plaintext highlighter-rouge">Configuration.clickViaJs</code> в то значение, которое вам подходит в большинстве случаев, и задавать параметр <code class="language-plaintext highlighter-rouge">ClickOptions</code> точечно - только там, где он необходим.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1173">issue 1173</a>.<br /> Спасибо <a href="https://github.com/dstekanov">Dmytro Stekanov</a> за <a href="https://github.com/selenide/selenide/pull/1226">PR 1226</a>.</p> <h2 id="добавили-универсальный-метод-скачивания-файла-с-параметром-downloadoptions">Добавили универсальный метод скачивания файла<br /> с параметром <code class="language-plaintext highlighter-rouge">DownloadOptions</code></h2> <p>Аналогичная история была с методом <code class="language-plaintext highlighter-rouge">$.download()</code>. Изначально он умел скачивать файлы только одним способом - через GET запрос. Потом селенид научился скачивать файлы через прокси. Недавно мы добавили третий способ - <code class="language-plaintext highlighter-rouge">FOLDER</code>.<br /> До сих пор способ скачивания можно было задать только через глобальную настройку <code class="language-plaintext highlighter-rouge">Configuration.fileDownload</code>.</p> <p>А теперь способ скачивания можно задавать через параметр в каждый вызов <code class="language-plaintext highlighter-rouge">$.download</code>, не меняя глобальную настройку:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">File</span> <span class="n">f</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"input"</span><span class="o">).</span><span class="na">download</span><span class="o">(</span><span class="nc">DownloadOptions</span><span class="o">.</span><span class="na">using</span><span class="o">(</span><span class="no">PROXY</span><span class="o">);</span> <span class="nc">File</span> <span class="n">f</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"input"</span><span class="o">).</span><span class="na">download</span><span class="o">(</span><span class="nc">DownloadOptions</span><span class="o">.</span><span class="na">using</span><span class="o">(</span><span class="no">PROXY</span><span class="o">).</span><span class="na">withTimeout</span><span class="o">(</span><span class="mi">9999</span><span class="o">));</span> <span class="nc">File</span> <span class="n">f</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"input"</span><span class="o">).</span><span class="na">download</span><span class="o">(</span><span class="nc">DownloadOptions</span><span class="o">.</span><span class="na">using</span><span class="o">(</span><span class="no">PROXY</span><span class="o">).</span><span class="na">withFilter</span><span class="o">(</span><span class="n">withExtension</span><span class="o">(</span><span class="s">"xls"</span><span class="o">)).</span><span class="na">withTimeout</span><span class="o">(</span><span class="mi">9999</span><span class="o">));</span> <span class="nc">File</span> <span class="n">f</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"input"</span><span class="o">).</span><span class="na">download</span><span class="o">(</span><span class="nc">DownloadOptions</span><span class="o">.</span><span class="na">using</span><span class="o">(</span><span class="no">FOLDER</span><span class="o">);</span> <span class="nc">File</span> <span class="n">f</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"input"</span><span class="o">).</span><span class="na">download</span><span class="o">(</span><span class="nc">DownloadOptions</span><span class="o">.</span><span class="na">using</span><span class="o">(</span><span class="no">FOLDER</span><span class="o">).</span><span class="na">withTimeout</span><span class="o">(</span><span class="mi">9999</span><span class="o">));</span> <span class="nc">File</span> <span class="n">f</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"input"</span><span class="o">).</span><span class="na">download</span><span class="o">(</span><span class="nc">DownloadOptions</span><span class="o">.</span><span class="na">using</span><span class="o">(</span><span class="no">FOLDER</span><span class="o">).</span><span class="na">withFilter</span><span class="o">(</span><span class="n">withExtension</span><span class="o">(</span><span class="s">"pdf"</span><span class="o">)).</span><span class="na">withTimeout</span><span class="o">(</span><span class="mi">9999</span><span class="o">));</span> </code></pre></div></div> <p>NB! Мы рекомендуем выставить настройку <code class="language-plaintext highlighter-rouge">Configuration.fileDownload</code> в то значение, которое вам подходит в большинстве случаев, и задавать параметр <code class="language-plaintext highlighter-rouge">DownloadsOptions</code> точечно - только там, где он необходим.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1259">issue 1259</a> и <a href="https://github.com/selenide/selenide/pull/1260">PR 1260</a>.</p> <h2 id="добавили-методы-для-работы-с-localstorage">Добавили методы для работы с LocalStorage</h2> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">Selenide</span><span class="o">.</span><span class="na">localStorage</span><span class="o">;</span> <span class="c1">// Очистить всё содержимое:</span> <span class="n">localStorage</span><span class="o">().</span><span class="na">clear</span><span class="o">();</span> <span class="c1">// Добавить значение:</span> <span class="n">localStorage</span><span class="o">().</span><span class="na">setItem</span><span class="o">(</span><span class="s">"username"</span><span class="o">,</span> <span class="s">"john"</span><span class="o">);</span> <span class="c1">// Проверить значение:</span> <span class="n">assertThat</span><span class="o">(</span><span class="n">localStorage</span><span class="o">().</span><span class="na">getItem</span><span class="o">(</span><span class="s">"username"</span><span class="o">)).</span><span class="na">isEqualTo</span><span class="o">(</span><span class="s">"john"</span><span class="o">);</span> <span class="c1">// Проверить количество элементов:</span> <span class="n">assertThat</span><span class="o">(</span><span class="n">localStorage</span><span class="o">().</span><span class="na">size</span><span class="o">()).</span><span class="na">isEqualTo</span><span class="o">(</span><span class="mi">1</span><span class="o">);</span> <span class="c1">// удалить значение:</span> <span class="n">localStorage</span><span class="o">().</span><span class="na">removeItem</span><span class="o">(</span><span class="s">"username"</span><span class="o">);</span> <span class="n">assertThat</span><span class="o">(</span><span class="n">localStorage</span><span class="o">().</span><span class="na">getItem</span><span class="o">(</span><span class="s">"username"</span><span class="o">)).</span><span class="na">isNull</span><span class="o">();</span> </code></pre></div></div> <p>Спасибо <a href="https://github.com/dstekanov">Dmytro Stekanov</a> за <a href="https://github.com/selenide/selenide/pull/1274">PR 1274</a>.</p> <h2 id="добавили-проверки-для-текст-элемента-без-потомков">Добавили проверки для текст элемента без потомков</h2> <p>Классическая селенидовская проверка <code class="language-plaintext highlighter-rouge">$.shouldHave(text("Hello, world"))</code> включает и текст самого элемента, и тексты всех его потомков.<br /> А иногда хочется проверить только текст самого элемента, без потомков. Для этого мы добавила две новых проверки:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">ownText</span><span class="o">(</span><span class="s">"Hello"</span><span class="o">));</span> <span class="c1">// Элемент должен содержать текст "Hello"</span> <span class="err">$</span><span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">exactOwnText</span><span class="o">(</span><span class="s">"Hello"</span><span class="o">));</span> <span class="c1">// Текст элемента должен быть "Hello" </span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1261">issue 1261</a> и <a href="https://github.com/selenide/selenide/pull/1262">PR 1262</a>.</p> <h2 id="ускорили-работу-с-большими-фильтрованными-коллекциями">Ускорили работу с большими фильтрованными коллекциями</h2> <p>В селениде есть удобные методы для работы с коллекциями элементов: их можно удобно отфильтровать, в них можно искать элементы или разом проверить, скажем, тексты всех элементов.</p> <p>Но если слишком злоупотреблять, можно написать слишком медленный тест. Например, вот так:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">ElementsCollection</span> <span class="n">list</span> <span class="o">=</span> <span class="err">$$</span><span class="o">(</span><span class="s">"li"</span><span class="o">).</span><span class="na">filter</span><span class="o">(</span><span class="n">visible</span><span class="o">);</span> <span class="c1">// На странице 100 элементов &lt;li&gt;</span> <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">10</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span> <span class="n">list</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">i</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">visible</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>Если на странице, предположим, 100 элементов <code class="language-plaintext highlighter-rouge">&lt;li&gt;</code>, то такой тест может очень долго работать.</p> <ul> <li>Ведь селенид на каждом шагу должен перегрузить элемент - вдруг его состояние изменилось!</li> <li>А чтобы перегрузить N-ный элемент коллекции, нужно перегрузить всю коллекцию (в селениуме ведь нет метода <code class="language-plaintext highlighter-rouge">WebDriver.findElement(index)</code>).</li> <li>А чтобы перегрузить фильтрованную коллекцию, нужно пройтись по всем её элементам и применить фильтр для каждого (в данном примере - вызвать <code class="language-plaintext highlighter-rouge">WebElement.isDisplayed()</code>).</li> </ul> <p><br /> Для сравнения, такой цикл работает гораздо быстрее:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">ElementsCollection</span> <span class="n">unfiltered</span> <span class="o">=</span> <span class="err">$$</span><span class="o">(</span><span class="s">"li"</span><span class="o">);</span> <span class="c1">// Нефльтрованная коллекция </span> <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">10</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span> <span class="n">unfiltered</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">i</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">visible</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>В этом релизе мы немного ускорили работу с коллекциями. Теперь Селенид фильтрует коллекцию умнее: чтобы получить <code class="language-plaintext highlighter-rouge">list.get(N)</code>, он применяет фильтр <code class="language-plaintext highlighter-rouge">visible</code> не для всех 100 элементов, а только для первых <code class="language-plaintext highlighter-rouge">&lt;N&gt;</code> элементов.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1266">issue 1266</a> и <a href="https://github.com/selenide/selenide/pull/1270">PR 1270</a>.</p> <p><br /> P.S. Напомню, что другой вариант ускорить тесты в таких случаях - использовать метод <code class="language-plaintext highlighter-rouge">snapshot</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">ElementsCollection</span> <span class="n">list</span> <span class="o">=</span> <span class="err">$$</span><span class="o">(</span><span class="s">"li"</span><span class="o">).</span><span class="na">filter</span><span class="o">(</span><span class="n">visible</span><span class="o">).</span><span class="na">snapshot</span><span class="o">();</span> <span class="c1">// snapshot() создаёт "слепок" коллекции. Селенид не будет её перегружать каждый раз. </span> <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">10</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span> <span class="n">list</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">i</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">visible</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>Но при использовании <code class="language-plaintext highlighter-rouge">snapshot</code> есть риск словить <code class="language-plaintext highlighter-rouge">StaleElementReferenceException</code>, если коллекция всё-таки обновилась во время цикла.</p> <h2 id="добавили-проверку-href">Добавили проверку “href”</h2> <p>Иногда хочется в тесте проверить, что у элемента <code class="language-plaintext highlighter-rouge">&lt;a&gt;</code> правильное значение атрибута <code class="language-plaintext highlighter-rouge">href</code>, т.е. ссылки.<br /> Для этого всегда можно было использовать метод <code class="language-plaintext highlighter-rouge">$("a").shouldHave(attribute("href", "/foo/bar/details.html")</code>.</p> <p>Проблема в том, что такая проверка очень неочевидно падает, потому что селениум возвращает абсолютный, а не относительный URL.<br /> Подробнее см. в докладе Алексея Баранцева <a href="http://www.youtube.com/watch?v=4dh--iD_zK8&amp;t=57m11s">“Заморочки в Selenium WebDriver”</a> с 57:11.</p> <p>Чтобы хоть немножко облегчить эту заморочку, мы добавили проверку “should have href” для ссылок:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">`$</span><span class="o">(</span><span class="s">"a"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">href</span><span class="o">(</span><span class="s">"/foo/bar/details.html"</span><span class="o">))</span><span class="err">`</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1272">issue 1272</a> и <a href="https://github.com/selenide/selenide/pull/1273">PR 1273</a>.</p> <h2 id="добавили-опцию-хрома-no-sandbox">Добавили опцию хрома “–no-sandbox”</h2> <p>Я где-то вычитал, что она сделает тесты на хроме стабильнее. Скрестим пальцы и будем надеяться.</p> <p>См. <a href="https://github.com/selenide/selenide/commit/3293956d">commit 3293956d</a></p> <h2 id="селенид-теперь-явно-кидает-ошибку">Селенид теперь явно кидает ошибку</h2> <p>… если не удалось создать папку для скачивания файлов.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1265">issue 1265</a> и commit 94ece98f](https://github.com/selenide/selenide/commit/94ece98f).</p> <h2 id="обновились-на-webdrivermanager-422">Обновились на WebDriverManager 4.2.2</h2> <p>См. <a href="https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md">WDM Changelog</a>.</p> <p><br /></p> <h2 id="видеообзор">Видеообзор</h2> <p>Смотрите <a href="https://youtu.be/txozPtQIqiE">видеообзор</a> данного релиза.</p> <h2 id="новости">Новости</h2> <p>Приходите 4-7 ноября 2020 на онлайн-конференцию <a href="https://heisenbug-moscow.ru/2020/msk/schedule/">Heisenbug</a>!</p> <p>Я там тоже буду выступать:</p> <ul> <li>Воркшоп “Как начать свой проект автоматизации с нуля (с божьей помощью и Selenide)” - для начинающих</li> <li>Доклад “Flaky tests. Метод” - для опытных</li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2020/09/26/selenide-5.15.0/ http://ru.selenide.org/2020/09/26/selenide-5.15.0 2020-09-26T00:00:00+00:00 Вышла Selenide 5.14.0 <p>Всем привет!</p> <p>Мы выпустили релиз <a href="https://github.com/selenide/selenide/milestone/101?closed=1">Selenide 5.14.0</a>.</p> <h2 id="стабилизировали-новый-способ-скачивания-файлов-folder">Стабилизировали новый способ скачивания файлов <code class="language-plaintext highlighter-rouge">FOLDER</code></h2> <p>… который появился в <a href="/2020/07/08/selenide-5.13.0/">Selenide 5.13.0</a>.</p> <p>Вот что поменялось в 5.14.0:</p> <ol> <li> <p>Каждый раз, когда селенид открывает браузер, он создаёт для него уникальную папку для скачиваний. Это помогает избежать ситуаций, когда параллельные тесты одновременно скачивают файлы в одну и ту же папку, и невозможно понять, где чей файл.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1220">issue 1220</a> и <a href="https://github.com/selenide/selenide/pull/1221">PR 1221</a>.</p> <ul> <li>Увы, это не работает для IE и Safari (которые в принципе не позволяют задать папку для скачивания файлов)</li> <li>Также это работает только для тех браузеров, которые открывает селенид.</li> <li>Если же вы сами открываете браузер и передаёте его селениду, вам нужно будет создать уникальную папку самостоятельно и передать её селениду: <ul> <li>Либо с помощью нового метода <code class="language-plaintext highlighter-rouge">setWebDriver(driver, proxy, downloadsFolder)</code>,</li> <li>либо конструктора <code class="language-plaintext highlighter-rouge">SelenideDriver(..., downloadsFolder)</code>.</li> </ul> </li> </ul> </li> <li>Перед началом каждого скачивания файла селенид очищает папку – см. <a href="https://github.com/selenide/selenide/pull/1252">PR 1252</a></li> <li>Селенид удаляет все пустые папки для скачиваний в конце тестов – см. <a href="https://github.com/selenide/selenide/pull/1247">PR 1247</a></li> </ol> <h2 id="добавили-проверку-shouldhaveitemwithtextany-text">Добавили проверку <code class="language-plaintext highlighter-rouge">$$.shouldHave(itemWithText("any text"))</code></h2> <p>В отличие от классической <code class="language-plaintext highlighter-rouge">$$.shouldHave(texts("text1", "text2"))</code>, она означает, что в коллекции есть хотя бы один элемент с данным текстом.</p> <p>Спасибо <a href="https://github.com/LuisOsv">Luis Serna</a> за <a href="https://github.com/selenide/selenide/pull/1194">PR 1194</a>.</p> <p>Кстати, это первый коммит в селенид аж из Боливии!</p> <h2 id="добавили-поддержку-браузера-safari">Добавили поддержку браузера Safari</h2> <p>Когда-то селенид поддерживал Safari, но тогда куча всего в нём не работало.<br /> В какой-то момент нам надоело с ним мучаться, и мы поддержку выпилили.<br /> Но сейчас попробовали новый подход. Вроде как завелось (не всё, конечно).</p> <p>Как обычно, достаточно просто прописать</p> <ol> <li><code class="language-plaintext highlighter-rouge">Configuration.browser = "safari";</code> либо</li> <li><code class="language-plaintext highlighter-rouge">-Dselenide.browser=safari</code></li> </ol> <p>Делитесь впечатлениями.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1236">issue 1236</a> и <a href="https://github.com/selenide/selenide/pull/1237">PR 1237</a>.</p> <h2 id="добавили-метод-selenidedriverscreenshotfilename">Добавили метод <code class="language-plaintext highlighter-rouge">SelenideDriver.screenshot(fileName)</code></h2> <p>Полезно, если вы создаёте “нестатический” вариант драйвера (<code class="language-plaintext highlighter-rouge">new SelenideDriver()</code>) и хотите снимать скриншоты.<br /> Теперь можно.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1166">issue 1166</a> и <a href="https://github.com/selenide/selenide/pull/1227">PR 1227</a>.</p> <h2 id="добавили-метод-selenidedriverscreenshotoutputtype">Добавили метод <code class="language-plaintext highlighter-rouge">SelenideDriver.screenshot(OutputType)</code></h2> <p>Иногда хочется получить скриншот в формате Base64. Например, этот формат хотят некоторые инструменты для сравниения скриншотов.</p> <p>Теперь их можно получить таким вызовом:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">String</span> <span class="n">screenshot</span> <span class="o">=</span> <span class="nc">Selenide</span><span class="o">.</span><span class="na">screenshot</span><span class="o">(</span><span class="nc">OutputType</span><span class="o">.</span><span class="na">BASE64</span><span class="o">);</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">decoded</span> <span class="o">=</span> <span class="nc">Base64</span><span class="o">.</span><span class="na">getDecoder</span><span class="o">().</span><span class="na">decode</span><span class="o">(</span><span class="n">screenshot</span><span class="o">);</span> <span class="nc">BufferedImage</span> <span class="n">img</span> <span class="o">=</span> <span class="nc">ImageIO</span><span class="o">.</span><span class="na">read</span><span class="o">(</span><span class="k">new</span> <span class="nc">ByteArrayInputStream</span><span class="o">(</span><span class="n">decoded</span><span class="o">));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1224">issue 1224</a> и <a href="https://github.com/selenide/selenide/pull/1231">PR 1231</a>.</p> <h2 id="теперь-селенид-снимает-скриншот-в-случае-падения-switchto">Теперь селенид снимает скриншот в случае падения <code class="language-plaintext highlighter-rouge">switchTo()</code></h2> <p>Как вы знаете, Селенид автоматически делает скриншот в случае падения тестов.<br /> Но мы обнаружили, что Селенид НЕ делал скриншот, если упал один из этих методов:</p> <ul> <li><code class="language-plaintext highlighter-rouge">switchTo(frame)</code></li> <li><code class="language-plaintext highlighter-rouge">switchTo(window)</code></li> <li><code class="language-plaintext highlighter-rouge">switchTo(alert)</code></li> </ul> <p>Теперь мы исправили эту досадную оплошность.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1190">issue 1190</a> и <a href="https://github.com/selenide/selenide/pull/1240">PR 1240</a>.</p> <h2 id="добавили-хрому-опцию---disable-dev-shm-usage">Добавили хрому опцию <code class="language-plaintext highlighter-rouge">--disable-dev-shm-usage</code></h2> <p>Мы тут вычитали, что без этой опции Chrome может крэшиться из-за out of memory error.</p> <ol> <li>Почему никто из вас на это не жаловался?</li> <li>Стало ли лучше после добавления это опции?</li> </ol> <p>P.S. Позже люди жаловались и на наличие этой опции. <a href="https://github.com/selenide/selenide/issues/1559">Эпопея</a> пока не окончена.</p> <h2 id="исправили-работу-sizzle-селекторов-на-страницах-с-dojojs-troopjs-и-тп">Исправили работу Sizzle селекторов на страницах с Dojo.js, troop.js и т.п.</h2> <p>См. <a href="https://github.com/selenide/selenide/issues/434">issue 434</a> и <a href="https://github.com/selenide/selenide/pull/1242">PR 1242</a>.</p> <h2 id="сделали-метод-tostring-безопаснее">Сделали метод <code class="language-plaintext highlighter-rouge">$.toString()</code> безопаснее</h2> <p>См. <a href="https://github.com/selenide/selenide/issues/1241">issue 1241</a> и <a href="https://github.com/selenide/selenide/pull/1245">PR 1245</a>.</p> <h2 id="улучшили-сообщение-об-ошибке-если-элемент-внезапно-пропал">Улучшили сообщение об ошибке, если элемент внезапно пропал</h2> <p>См. <a href="https://github.com/selenide/selenide/issues/1013">issue 1013</a> и <a href="https://github.com/selenide/selenide/pull/1239">PR 1239</a>.</p> <h2 id="обновились-на-webdrivermanager-410">Обновились на WebDriverManager 4.1.0</h2> <p>См. <a href="https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md">WDM Changelog</a>.</p> <p><br /></p> <h2 id="видеообзор">Видеообзор</h2> <p>Смотрите <a href="https://youtu.be/x0KWgnjxsl4">видеообзор</a> данного релиза.</p> <h2 id="новости">Новости</h2> <ul> <li>Ничоси! Курс на Udemy “<a href="https://www.udemy.com/course/selenium-selenide-test-automation-engineer/">Selenium и Selenide для начинающих Automation QA, QC на Java</a>”</li> <li>Про селенид <a href="https://www.youtube.com/watch?v=WNzTuYFd8oI">на немецком</a></li> <li>Пример проекта <a href="https://github.com/d3m0/automation">на Selenide+Selenoid+Docker</a> от <a href="https://github.com/d3m0">d3m0</a></li> <li>Ещё пример: <a href="https://github.com/Crushpowerx/JavaMavenSelenideAllureScreenDiffExample">сравнение скриншотов с Selenide+Allure+Ashot+Screen Diff Plugin</a> от <a href="https://github.com/Crushpowerx/">Evgeniy Asovin</a></li> <li>Ещё пример: <a href="https://github.com/qaschevychelov/giphyTest">Selenide + Appium + Allure + TestNG</a> от <a href="https://github.com/qaschevychelov/">qaschevychelov</a></li> <li>Сравнение Selenide и Selenium 2019 года: <a href="https://www.appliedtech.ru/en/web-tools-for-ui-testing-selenium-or-selenide.html">Choosing tools for UI testing: Selenium or Selenide?</a> - 17.09.2019</li> <li>Статья Jakub Skibiński в блоге компании Sonalake: <a href="https://sonalake.com/latest/selenide-a-powerful-testing-framework/">Selenide: A Powerful Testing Framework</a> - 19.06.2020</li> <li>Статья “<a href="https://habr.com/ru/company/maxilect/blog/499810/">Почему мы перешли на Selenide, попутно написав более 200 новых автотестов</a>” - 30.04.2020</li> <li><a href="https://medium.com/@maxilect_pr/selenide-our-experience-11240f9ce10c">Switch from Serenity to Selenide</a> - 22.05.2020 от <a href="https://medium.com/@maxilect_pr">Yuri Kudryavtsev</a> (Maxilect company)</li> </ul> <p>И целая серия статей от <a href="https://medium.com/@alexspush">Alexander Pushkarev</a>:</p> <ul> <li><a href="https://medium.com/@alexspush/test-automation-framework-architecture-part-2-1-layered-architecture-example-62a0011d3329">Test automation framework architecture — Layered architecture example with vanilla JUnit + Selenide</a></li> <li><a href="https://medium.com/@alexspush/ui-automation-for-mortal-elegant-page-objects-with-java-and-selenide-3122b17dc473">UI Automation for mortals: elegant Page Objects with Java and Selenide</a></li> <li><a href="https://medium.com/@alexspush/an-alternative-to-ubiquitous-ui-level-checking-subcutaneous-tests-8d29e8883fc2">Effective test automation: subcutaneous tests as a faster alternative to Selenium-driven testing</a></li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2020/08/17/selenide-5.14.0/ http://ru.selenide.org/2020/08/17/selenide-5.14.0 2020-08-17T00:00:00+00:00 Вышла Selenide 5.13.0 <p>Всем привет!</p> <p>Лето не повод расслабляться! Мы выпустили релиз <a href="https://github.com/selenide/selenide/milestone/98?closed=1">Selenide 5.13.0</a>.</p> <p>Будьте осторожны, он может сломать ваши тесты (если они были неаккуратно сделаны).</p> <ul class="blogpost-menu"> <li><a href="#should-have-empty-text">Запретили <code class="language-plaintext highlighter-rouge">shouldHave(text(""))</code></a></li> <li><a href="#remove-unneeded-allure-logs">Убрали лишние логи из аллюра</a></li> <li><a href="#improve-collection-error-messages">Сообщение об ошибках для коллекций</a></li> <li><a href="#fix-upload-without-form">Скачиваем файлы без <code class="language-plaintext highlighter-rouge">&lt;form&gt;</code></a></li> <li><a href="#download-files-with-quotes">Скачиваем файлы с кавычками в имени</a></li> <li><a href="#write-webdriver-logs-to-file">Пишем логи вебдрайвера в файл</a></li> <li><a href="#new-file-download-mode-folder">Новый способ скачивания файлов <code class="language-plaintext highlighter-rouge">FOLDER</code></a></li> <li><a href="#get-wrapped-element-waits-for-element">Метод <code class="language-plaintext highlighter-rouge">$.getWrappedElement()</code> снова ждёт появления элемента</a></li> <li><a href="#statistics">Статистика</a></li> </ul> <h2 id="should-have-empty-text">Метод <code class="language-plaintext highlighter-rouge">$.shouldHave(text(""))</code> кидает ошибку</h2> <p>Возможно, самый популярный метод селенида - это <code class="language-plaintext highlighter-rouge">$.shouldHave(text("что-то"))</code>. Но даже если вы используете его каждый день, возможно, вы не подозреваете, что он проверяет <em>подстроку</em>. Т.е. проверка <code class="language-plaintext highlighter-rouge">$("h1").shouldHave(text("ello"))</code> сработает и для элемента <code class="language-plaintext highlighter-rouge">&lt;h1&gt;Hello World&lt;/h1&gt;</code>.</p> <p>Частный случай такой проверки - <code class="language-plaintext highlighter-rouge">$("h1").shouldHave(text(""))</code>. Такую проверку пройдёт <strong>любой элемент</strong>, ведь любая строка содержит пустую подстроку. То есть такая проверка просто <em>бессмысленна</em>.</p> <blockquote> <p>Если вам нужно убедиться, что текст пустой, используйте <code class="language-plaintext highlighter-rouge">$("h1").shouldHave(exactText(""))</code> или <code class="language-plaintext highlighter-rouge">$("h1").shouldBe(empty)</code>.</p> </blockquote> <p>Мы хотим вам помочь избежать этой типичной проблемы и избавиться от бессмысленных проверок. Для этого теперь селенид будет бросать ошибку, если вы попытаетесь передать в метод <code class="language-plaintext highlighter-rouge">text("")</code> пустую строку или null.</p> <blockquote> <p>Я попробовал Selenide 5.13.0 на своём рабочем проекте и внезапно нашёл тестов 20-30, которые падали с этой ошибкой. И это всё были логические ошибки в тестах! Вот какое полезное изменение вас ждёт. :)</p> </blockquote> <p>См. <a href="https://github.com/selenide/selenide/issues/1156">issue 1156</a>.<br /> Спасибо <a href="https://github.com/eaxdev">Roman S.A.</a> за <a href="https://github.com/selenide/selenide/pull/1186">PR 1186</a>.</p> <p><strong>UPD</strong><br /> Позже мы добавили <a href="/2022/08/04/selenide-6.7.0/#holy-whole-string">настройку <code class="language-plaintext highlighter-rouge">FULL_TEXT</code></a>, заставляющую Selenide проверять строку целиком, на не подстроку.</p> <h2 id="remove-unneeded-allure-logs">Убрали л