Selenide Selenide - Andrei Solntsev http://ru.selenide.org/rss http://ru.selenide.org 2023-05-30T06:39:08+00:00 2023-05-30T06:39:08+00:00 1800 Вышла 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> <h2 id="remove-unneeded-allure-logs">Убрали лишние логи из аллюра</h2> <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="n">bySelector</span><span class="o">).</span><span class="na">findAll</span><span class="o">(</span><span class="nc">BySelector</span><span class="o">).</span><span class="na">filter</span><span class="o">(</span><span class="n">condtion</span><span class="o">);</span> </code></pre></div></div> <p>(на самом деле не только в аллюре, но и в обычном селенидовском <code class="language-plaintext highlighter-rouge">TextReport</code>)</p> <p>Теперь мы убрали эти двойные логи. Пришло кое-чего порефакторить, некоторые сообщения об ошибках изменились.<br /> Но вроде бы всё стало лучше. Если заметили ухудшение - смело сообщайте.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/997">issue 997</a> и <a href="https://github.com/selenide/selenide/pull/1193">PR 1193</a>.</p> <h2 id="improve-collection-error-messages">Улучшили сообщение об ошибках для коллекций</h2> <p>Ещё одна похожая история, где мы немного изменили формат ошибок при поиске элементов внутри коллекций.<br /> По идее теперь должно быть понятнее, что внутри чего не удалось найти.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/967">issue 967</a> и <a href="https://github.com/selenide/selenide/pull/1189">PR 1189</a>.</p> <h2 id="fix-upload-without-form">Починили загрузку файлов вне тэга <code class="language-plaintext highlighter-rouge">&lt;form&gt;</code></h2> <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"</span><span class="o">).</span><span class="na">uploadFile</span><span class="o">(</span> <span class="k">new</span> <span class="nf">File</span><span class="o">(</span><span class="s">"a.txt"</span><span class="o">),</span> <span class="k">new</span> <span class="nf">File</span><span class="o">(</span><span class="s">"b.txt"</span><span class="o">),</span> <span class="k">new</span> <span class="nf">File</span><span class="o">(</span><span class="s">"c.txt"</span><span class="o">)</span> <span class="o">);</span> </code></pre></div></div> <p>Для этой загрузки мы в своё время сделали в селениде хитрый JS хак. Оказалось, что этот хак предполагал, что <code class="language-plaintext highlighter-rouge">&lt;input&gt;</code> для загрузки файла должен быть внутри тэга <code class="language-plaintext highlighter-rouge">&lt;form&gt;</code>. Что как бы логично.<br /> Но оказалось, что не у всех так.</p> <p>В общем, теперь мы упростили хак и убрали зависимость от тэга <code class="language-plaintext highlighter-rouge">&lt;form&gt;</code>.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/943">issue 943</a> и <a href="https://github.com/selenide/selenide/pull/1188">PR 1188</a>.</p> <h2 id="download-files-with-quotes">Научились скачивать файлы с кавычками в имени</h2> <p>… и другими нехорошими символами.</p> <p>Оказывается, есть и такие чудаки, которые генерируют файлы, в имени которых есть кавычки. Линукс и Мак вполне умеют сохранять такие файлы, а вот винда никак. Теперь селенид заменяет кавычки и другие нехорошие символы на подчёркивания (как делают все основные браузеры).</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1196">issue 1196</a> и <a href="https://github.com/selenide/selenide/pull/1199">PR 1199</a>.</p> <h2 id="write-webdriver-logs-to-file">Научили вебдрайвер писать свои логи в файл</h2> <p>До сих пор вебдрайвер, запускаемый селенидом, по умолчанию не писали никуда свои логи. Вам нужно было включать их явно.</p> <p>Теперь же селенид включает логи вебдрайвера. Логи пишутся в файлы вида <code class="language-plaintext highlighter-rouge">build/reports/tests/webdriver.ts_pid_tid.log</code>.<br /> Полный путь к файлу вы можете узнать из лога, который пишет селенид каждый раз при открытии браузера:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">INFO</span> <span class="nc">Write</span> <span class="n">webdriver</span> <span class="n">logs</span> <span class="nl">to:</span> <span class="o">/</span><span class="n">andrei</span><span class="o">/</span><span class="n">build</span><span class="o">/</span><span class="n">reports</span><span class="o">/</span><span class="n">tests</span><span class="o">/</span><span class="n">webdriver</span><span class="o">.</span><span class="mi">1594248139109_18125_1</span><span class="o">.</span><span class="na">log</span> </code></pre></div></div> <p>Когда в следующий раз будете изучать аномальное поведение вебдрайвера, не забудьте туда заглянуть.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1206">issue 1206</a> и <a href="https://github.com/selenide/selenide/pull/1207">PR 1207</a>.</p> <h2 id="new-file-download-mode-folder">Добавили новый способ скачивания файлов <code class="language-plaintext highlighter-rouge">FOLDER</code></h2> <p>Как вы знаете, до сих пор в селениде было два способа скачивания файлов: <code class="language-plaintext highlighter-rouge">HTTPGET</code> и <code class="language-plaintext highlighter-rouge">PROXY</code>. См. <a href="/2019/12/10/advent-calendar-download-files/">пост в нашем блоге</a>.</p> <ul> <li><code class="language-plaintext highlighter-rouge">HTTPGET</code> - самый простой и надёжный. Но умеет скачивать только файлы с ссылки вида <code class="language-plaintext highlighter-rouge">&lt;a href&gt;</code>.</li> <li><code class="language-plaintext highlighter-rouge">PROXY</code> - универсальный и мощный способ. Но при удалённом запуске требует доступа с машины браузера к машине тестов. Что порой вызывает сложности и поклонников Селеноида и Грида.</li> </ul> <p>Теперь появился третий способ: <code class="language-plaintext highlighter-rouge">FOLDER</code>.</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="nc">FileDownloadMode</span><span class="o">.</span><span class="na">FOLDER</span><span class="o">;</span> </code></pre></div></div> <p>Работает он просто:</p> <ol> <li>Кликает элемент</li> <li>Смотрит, какие новые файлы появились в папке <code class="language-plaintext highlighter-rouge">build/downloads</code></li> <li>Если таких файлов несколько, пытается угадать, какой из них подходит лучше всего.</li> </ol> <p>Рабочий пример всегда можно найти <a href="https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/FileDownloadToFolderTest.java">в тестах самого селенида</a>.</p> <p><br /> P.S. Будем пока считать этот способ <em>экспериментальным</em>, поскольку есть нюансы:</p> <ol> <li>Работает надёжно при локальном запуске в один поток</li> <li>При параллельном запуске одновременные тесты могут скачивать файлы в одну и ту же папку, и тогда селенид не сможет определить, кому какой файл отдать.</li> <li>При удалённом запуске этот способ вообще пока не работает. Тесты-то здесь, а папка там!</li> <li>Поддерживаются Chrome, Firefox, Edge, Opera. Не поддерживаются IE и Safari (у в принципе нет возможности задать папку для скачивания файлов).</li> </ol> <p>Мы будем работать над этим, а вы делитесь своими соображениями, как разрулить вышеозначенные проблемы.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1212">issue 1212</a>, <a href="https://github.com/selenide/selenide/pull/1213">PR 1213</a> и <a href="https://github.com/selenide/selenide/pull/1215">PR 1215</a>.</p> <p>UPD Позже этот метод скачивания был доработан, и теперь его смело можно использовать в проектах.</p> <h2 id="get-wrapped-element-waits-for-element">Метод <code class="language-plaintext highlighter-rouge">$.getWrappedElement()</code> снова ждёт появления элемента</h2> <p>Вряд ли вам это интересно, но упомянуть обязан. По сути мы откатили одно недавнее изменение.</p> <p>Допустим, у вас есть такой код:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">SelenideElement</span> <span class="n">button</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"button"</span><span class="o">);</span> <span class="n">executeJavascript</span><span class="o">(</span><span class="s">"arguments[0].click()"</span><span class="o">,</span> <span class="n">button</span><span class="o">);</span> </code></pre></div></div> <p>где <code class="language-plaintext highlighter-rouge">button</code>, допустим, появляется на экране с задержкой.<br /> Всю жизнь этот метод ждал появления кнопки, и лишь тогда кликал. В Selenide 5.11 нас укусила какая-то собака, и мы сделали так, чтобы не ждал. Никто почему-то не жаловался, а вот в моём рабочем проекте несколько тестов упали.</p> <p>В общем, теперь мы вернули обратно старое поведение. Теперь снова ждёт.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1191">issue 1191</a> и <a href="https://github.com/selenide/selenide/pull/1203">PR 1203</a>.</p> <h2 id="upgrade-to-bup-2.1.1">Обновились до BrowserUpProxy 2.1.1</h2> <p>Ну вдруг.</p> <p>Обновляйтесь, пробуйте, делитесь впечатлениями!</p> <h2 id="statistics">Статистика</h2> <p>И моё любимое: статистика скачиваний селенида.<br /> Мы пробили потолок <strong>в 160 тысяч в месяц</strong>!</p> <center> <img src="/images/2020/07/selenide.downloads.png" width="800" /> </center> <p><br /> и <strong>31+ тысяча уникальных айпишников</strong>:</p> <center> <img src="/images/2020/07/selenide.unique-ips.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/2020/07/08/selenide-5.13.0/ http://ru.selenide.org/2020/07/08/selenide-5.13.0 2020-07-08T00:00:00+00:00 Вышла Selenide 5.12.2 <p>Всем привет!</p> <p>Ловите ещё один мини-релиз <a href="https://github.com/selenide/selenide/milestone/99?closed=1">Selenide 5.12.2</a>.</p> <h2 id="подправили-аннотации-nonnull">Подправили аннотации @Nonnull</h2> <p>… для некоторых методов <code class="language-plaintext highlighter-rouge">SelenideElement</code>.</p> <p>После обновления на Selenide 5.12.0 некоторые пользователи котлина начали жаловаться, что их проекты переставил компилироваться.<br /> Всё дело в том, что мы пометили все методы <code class="language-plaintext highlighter-rouge">SelenideElement</code> аннотациями <code class="language-plaintext highlighter-rouge">@Nullable</code>/<code class="language-plaintext highlighter-rouge">@Nonnull</code>, а котлин к ним чуток.</p> <p>Для следующих методов мы теперь прописали <code class="language-plaintext highlighter-rouge">@Nonnull</code>, потому что дополнительная проверка показала, что они никогда не возвращают null:</p> <ul> <li><code class="language-plaintext highlighter-rouge">$.getText()</code></li> <li><code class="language-plaintext highlighter-rouge">$.text()</code></li> <li><code class="language-plaintext highlighter-rouge">$.innerText()</code></li> <li><code class="language-plaintext highlighter-rouge">$.innerHtml()</code></li> <li><code class="language-plaintext highlighter-rouge">$.getSelectedText()</code></li> </ul> <p>Теперь в котлине их можно по-прежнему пихать в ненулевые переменные (хоть мне и кажутся сомнительными такие конструкции в тестах).</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1179">issue 1179</a> и <a href="https://github.com/selenide/selenide/pull/1181">PR 1181</a>.</p> <h2 id="исправили-работу-настройки-holdbrowseropentrue">Исправили работу настройки <code class="language-plaintext highlighter-rouge">holdBrowserOpen=true</code></h2> <p>Эта настройка срабатывала не всегда. Уже давно. <br /> И мы давно об этом знали, но забывали, потому что никто нам issue на гитхабе не заводил. :(</p> <p>В общем, исправили. При заданной настройке <code class="language-plaintext highlighter-rouge">Configuration.holdBrowserOpen=true</code> браузер остаётся открытым после окончания тестов и вообще всех потоков.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1172">issue 1172</a> и <a href="https://github.com/selenide/selenide/pull/1176">PR 1176</a>.</p> <h2 id="видосики">Видосики</h2> <ul> <li>Видео <a href="https://meetup.jugru.org/qa-heisenbug-breakfast-2">Тяжелое утро с Heisenbug #2</a> со мной. Вопросы, до которых обычно на конференциях не до.</li> <li>Всеволод Брекелов и Артём Ерошенко в <a href="https://meetup.jugru.org/qa-survival-bias-4">“Ошибке выжившего #4”</a> в прямом эфире пишут экспорт Record&amp;Play в Selenide. Представляете!</li> <li>Мы опубликовали <a href="https://github.com/selenide/selenide/wiki/Selenide-Roadmap">Selenide Roadmap</a>. Ждём ваших отзывов!</li> </ul> <h2 id="новости">Новости</h2> <p>Ура!</p> <p>Свершилось!</p> <p>Мы опубликовали <a href="https://github.com/selenide/selenide-for-selenium-ide">плагин для Selenium IDE</a>, который умеет <strong>экспортировать код в Selenide</strong>.</p> <ul> <li><a href="https://chrome.google.com/webstore/detail/selenide-for-selenium-ide/nlkfobhoffngaakgdbkdnmmjcchibcba">для Chrome</a></li> <li><a href="https://addons.mozilla.org/ru/firefox/addon/selenide-for-selenium-ide/">для Firefox</a></li> </ul> <p>Мы скоро напишем об этом отдельную статью.</p> <p>Большое спасибо <a href="https://github.com/dstekanov">Dmytro Stekanov</a> за этот исторический для селенида момент!</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2020/05/29/selenide-5.12.2/ http://ru.selenide.org/2020/05/29/selenide-5.12.2 2020-05-29T00:00:00+00:00 Вышла Selenide 5.12.1 <p>Всем привет!</p> <p>По горячим следам вы выпустили багфикс релиз <a href="https://github.com/selenide/selenide/milestone/97?closed=1">Selenide 5.12.1</a> с парочкой мелких исправлений для <a href="/2020/05/23/selenide-5.12.0/">Selenide 5.12.0</a>.</p> <h2 id="исправили-concurrent-modification-exception-при-инициализации-вебдрайвера">Исправили <em>Concurrent modification exception</em> при инициализации вебдрайвера</h2> <p>См. <a href="https://github.com/selenide/selenide/issues/1170">issue 1170</a> и <a href="https://github.com/selenide/selenide/pull/1171">PR 1171</a>.</p> <h2 id="исправили-мержинг-настройки-excludeswitches-разных-типов">Исправили мержинг настройки “excludeSwitches” разных типов</h2> <p>Оказывается, настройку <code class="language-plaintext highlighter-rouge">excludeSwitches</code> можно задать и как массив, и как список:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">chromeOptions</span><span class="o">.</span><span class="na">setExperimentalOption</span><span class="o">(</span><span class="s">"excludeSwitches"</span><span class="o">,</span> <span class="k">new</span> <span class="nc">String</span><span class="o">[]{</span><span class="s">"enable-automation"</span><span class="o">,</span> <span class="s">"load-extension"</span><span class="o">});</span> <span class="n">chromeOptions</span><span class="o">.</span><span class="na">setExperimentalOption</span><span class="o">(</span><span class="s">"excludeSwitches"</span><span class="o">,</span> <span class="n">asList</span><span class="o">(</span><span class="s">"enable-automation"</span><span class="o">,</span> <span class="s">"load-extension"</span><span class="o">));</span> </code></pre></div></div> <p>Селенид 5.12.0 ломался, если задать вперемежку и так, и так. Починили.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1169">issue 1169</a> и <a href="https://github.com/selenide/selenide/pull/1174">PR 1174</a>.</p> <h2 id="новости">Новости</h2> <ul> <li>Мы опубликовали <a href="https://github.com/selenide/selenide/wiki/Selenide-Roadmap">Selenide Roadmap</a>. Ждём ваших отзывов!</li> <li>Видео с митапа <a href="https://www.youtube.com/watch?v=1d-nKyeTH2Y">pro:TEST</a> - Чехия, 28.04.2020</li> <li>Видео с митапа <a href="https://www.youtube.com/watch?v=aFqZ6dbUJIw&amp;feature=emb_logo">QA meetup</a> - Словакия, 12.05.2020</li> <li>Всеволод Брекелов и Артём Ерошенко запустили шоу <a href="https://meetup.jugru.org/qa-survival-bias-1">“Ошибка выжившего”</a>. Я посмотрел первые 4 выпуска - годно!</li> <li>Ребята и девчонки из jug.ru запустили шоу “Тяжелое утро с Heisenbug”.<br /> Ближайший выпуск будет <strong>со мной</strong>, ура-ура! <a href="https://meetup.jugru.org/qa-heisenbug-breakfast-2">27 мая 2020</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/05/25/selenide-5.12.1/ http://ru.selenide.org/2020/05/25/selenide-5.12.1 2020-05-25T00:00:00+00:00 Вышла Selenide 5.12.0 <p>Всем привет!</p> <p>Ура, релиз <a href="https://github.com/selenide/selenide/milestone/95?closed=1">Selenide 5.12.0</a>.</p> <p>Большая часть изменений касается настроек браузеров.</p> <h2 id="порешали-старинную-проблему-с-configurationbrowsercapabilities">Порешали старинную проблему с <code class="language-plaintext highlighter-rouge">Configuration.browserCapabilities</code></h2> <p>Люди давно уже жаловались на то, что часть настроек в <code class="language-plaintext highlighter-rouge">ChromeOptions</code> теряется (при некоторых условиях). Вызвана она была <a href="https://github.com/SeleniumHQ/selenium/issues/5279">старой багой в Selenium</a>, которой никто особо не занимается. И мы не хотели ввязываться.</p> <p>Но кажется, нам удалось найти простой костыль.</p> <ul> <li>Если вам помогло - делитесь.</li> <li>Если не помогло - тем более делитесь, будем докостыливать дальше.</li> </ul> <p>См. <a href="https://github.com/selenide/selenide/issues/676">issue 676</a>, <a href="https://github.com/selenide/selenide/issues/1097">issue 1097</a> и <a href="https://github.com/selenide/selenide/pull/1155">PR 1155</a>.</p> <p>Отдельное спасибо за попытки, которые не попали в релиз, но навели нас на итоговое решение:</p> <ul> <li>Спасибо <a href="https://github.com/BorisOsipov">Boris Osipov</a> за <a href="https://github.com/selenide/selenide/pull/1103">PR #1103</a></li> <li>Спасибо <a href="https://github.com/SeleniumTestAB">SeleniumTestAB</a> за <a href="https://github.com/selenide/selenide/pull/1095">PR #1095</a></li> </ul> <h2 id="выключили-раздражающий-диалог-save-password">Выключили раздражающий диалог “save password?”</h2> <p>См. <a href="https://github.com/selenide/selenide/issues/1133">issue 1133</a> и <a href="https://github.com/selenide/selenide/pull/1134">PR 1134</a>.</p> <h2 id="добавили-режим-эмуляции-мобильника-в-гриде">Добавили режим “эмуляции мобильника” в гриде</h2> <p>Как вы знаете, в Selenide 5.6.1 появилась возможность запускать хром в режиме “эмуляции мобильного браузера”:</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="nc">Dchromeoptions</span><span class="o">.</span><span class="na">mobileEmulation</span><span class="o">=</span><span class="s">"deviceName=Nexus 5"</span> </code></pre></div></div> <p>Но эта опция срабатывала только при локальном запуске хрома, и не передавалась при запуске хрома в гриде.<br /> Теперь мы это починили: в грид передаются все настройки хрома, которые используются и при локальном запуске (кроме “папки для скачивания файлов”).</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1109">issue 1109</a> и <a href="https://github.com/selenide/selenide/pull/1163">PR 1163</a>.</p> <h2 id="упростили-сетап-firefox-теперь-без-профиля">Упростили сетап Firefox: теперь без профиля</h2> <p>При открытии браузера Firefox селенид создавал ему профиль (<code class="language-plaintext highlighter-rouge">FirefoxProfile</code>) - как минимум, чтобы задать папку для скачивания файлов.<br /> Оказалось, что использование профиля накладывает некоторые ограничения, и вообще не нужно (вроде как когда-то он был нужен для legacy firefox driver).</p> <p>Теперь мы по умолчанию обходимся без профиля:</p> <ol> <li>Папку для скачивания файлов создаём через <code class="language-plaintext highlighter-rouge">firefoxOptions.addPreference("browser.download.dir")</code></li> <li>Создаём профиль, только если вы специально задали системные свойства, начинающиеся на <code class="language-plaintext highlighter-rouge">"firefoxprofile."</code>.</li> </ol> <p>См. <a href="https://github.com/selenide/selenide/issues/1139">issue 1139</a> и <a href="https://github.com/selenide/selenide/pull/1165">PR 1165</a>.</p> <h2 id="задаём-настройку-accept_insecure_certs-для-версий-edge-построенных-на-движке-chromium">Задаём настройку <code class="language-plaintext highlighter-rouge">"ACCEPT_INSECURE_CERTS"</code> для версий Edge, построенных на движке chromium</h2> <p>Начиная с какой-то версии, браузеры IE и Edge перестали поддерживать настройку <code class="language-plaintext highlighter-rouge">"ACCEPT_INSECURE_CERTS"</code> (разрешение самоподписанных SSL сертификатов). И мы выпилили эту настройку для IE и Edge (в Selenide 5.9.0).</p> <p>Но оказалось, что более поздние версии Edge, которые построены на движке Chromium, снова начали её поддерживать.<br /> Поэтому мы вернули настройку <code class="language-plaintext highlighter-rouge">"ACCEPT_INSECURE_CERTS"</code> для версий Edge 75 и выше.</p> <p>Важно: версию Edge селенид может узнать, только если EdgeDriver был скачан с помощью WebDriverManager (что в селениде случается по умолчанию).</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1093">issue 1093</a> и <a href="https://github.com/selenide/selenide/pull/1167">PR 1167</a>.</p> <h2 id="обновились-на-webdrivermanager-400">Обновились на WebDriverManager 4.0.0</h2> <ul> <li>Поддержка Firefox 76</li> <li>Поддержка Edge 81, 83, 84</li> <li>Обновили Apache HttpClient с 4.x на 5.0</li> </ul> <p>См. <a href="https://github.com/selenide/selenide/pull/1149">PR 1149</a> и <a href="https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md">WDM Changelog</a>.</p> <h2 id="обновились-на-browserup-proxy-core210">Обновились на browserup-proxy-core:2.1.0</h2> <p>Ну мало ли.</p> <h2 id="исправили-имя-папки-для-скриншота-emptymethod">Исправили имя папки для скриншота ‘emptyMethod’</h2> <p>Проблема касалась только JUnit 5.</p> <p>Спасибо <a href="https://github.com/dengayevskiy-sb">Denis Gaievsky</a> за <a href="https://github.com/selenide/selenide/pull/1138">PR 1138</a></p> <h2 id="расставили-аннотации-nullable-и-nonnull">Расставили аннотации <code class="language-plaintext highlighter-rouge">@Nullable</code> и <code class="language-plaintext highlighter-rouge">@Nonnull</code></h2> <p>Это поможет IDEA (и надеюсь, другим IDE) лучше подсвечивать косяки в ваших тестах. <br /> А также это поможет пользователям Kotlin правильно использовать nullable/non-nullable типы.</p> <p>И снова спасибо <a href="https://github.com/jreznot">Yuriy Artamonov</a> за <a href="https://github.com/selenide/selenide/pull/1140">PR 1140</a> и <a href="https://github.com/selenide/selenide/pull/1144">PR 1144</a>!</p> <h2 id="новости">Новости</h2> <ul> <li>Мы опубликовали <a href="https://github.com/selenide/selenide/wiki/Selenide-Roadmap">Selenide Roadmap</a>. Ждём ваших отзывов!</li> <li>Видео с митапа <a href="https://www.youtube.com/watch?v=1d-nKyeTH2Y">pro:TEST</a> - Чехия, 28.04.2020</li> <li>Видео с митапа <a href="https://www.youtube.com/watch?v=aFqZ6dbUJIw&amp;feature=emb_logo">QA meetup</a> - Словакия, 12.05.2020</li> <li>Всеволод Брекелов и Артём Ерошенко запустили шоу <a href="https://meetup.jugru.org/qa-survival-bias-1">“Ошибка выжившего”</a>. Я посмотрел первые 4 выпуска - годно!</li> <li>Ребята и девчонки из jug.ru запустили шоу “Тяжелое утро с Heisenbug”.<br /> Ближайший выпуск будет <strong>со мной</strong>, ура-ура! <a href="https://meetup.jugru.org/qa-heisenbug-breakfast-2">27 мая 2020</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/05/23/selenide-5.12.0/ http://ru.selenide.org/2020/05/23/selenide-5.12.0 2020-05-23T00:00:00+00:00 Вышла Selenide 5.11.1 <p>Всем привет!</p> <p>Похоже, релиз <a href="https://github.com/selenide/selenide/milestone/94?closed=1">Selenide 5.11.0</a> всё-таки сломал слишком много устоев, и мы решили сбавить обороты. :)</p> <p>Меняем ваше возмущение на <a href="https://github.com/selenide/selenide/milestone/96?closed=1">Selenide 5.11.1</a>.</p> <h2 id="slf4j">SLF4J</h2> <p>Народные массы возмутил тот факт, что в версии 5.11.0 селенид безусловно стал требовать правильной зависимости slf4j. Народные массы не хотят настраивать slf4j и в гробу видали наши логи. :)</p> <p>Для нас это было неожиданно, но мы идём навстречу трудящимся.</p> <p>Теперь селенид требует slf4j не всегда, а только в тех редких случаях, когда без него точно никак. А именно, если вы включите <a href="/2016/09/26/selenide-3.10/">фичу <code class="language-plaintext highlighter-rouge">TextReport</code></a>.</p> <h2 id="because-we-can">because we can!</h2> <p>В Selenide 5.11.0 мы сделали одну (почти незаметную) багу, связанную с использованием <code class="language-plaintext highlighter-rouge">because</code>. А именно,</p> <ul> <li><code class="language-plaintext highlighter-rouge">$("blah").shouldNot(exist)</code> - не падает (это ок)</li> <li><code class="language-plaintext highlighter-rouge">$("blah").shouldNot(exist.because("we can"))</code> - падает (а вот это не ок)</li> </ul> <p>Слово <code class="language-plaintext highlighter-rouge">because</code> оказалось несовместимым с отрицанием. Теперь мы это исправили, и обе строчки не падают.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1130">issue 1130</a> и <a href="https://github.com/selenide/selenide/pull/1131">1131</a>.</p> <h2 id="сбросили-16-мегабайт">Сбросили 16 мегабайт</h2> <p>Оказывается, среди зависимостей селенида затесался 16-мегабайтный файл <code class="language-plaintext highlighter-rouge">checker.jar</code>.<br /> Мы с лёгкостью от него избавились.</p> <p>Спасибо <a href="https://github.com/jreznot">Yuriy Artamonov</a> за <a href="https://github.com/selenide/selenide/pull/1128">PR 1128</a>.</p> <h2 id="новости">Новости</h2> <p>Во вторник 28 апреля я буду выступать на чешском митапе <a href="https://www.meetup.com/protest_cz/events/270022839/">[pro:]TEST!</a><br /> Поскольку митап онлайн, участвовать будут все желающие. Можете позвать друзей, которые ещё не знают про селенид!</p> <ul> <li>Язык: ломаный английский</li> <li>Дата: 28.04.2020, 18:00 GMT+2</li> <li>Уровень: скорее для начинающих</li> <li>Ссылки: <a href="https://bit.ly/protest84invitation">Анонс</a> / <a href="https://www.youtube.com/watch?v=1d-nKyeTH2Y&amp;feature=youtu.be">Трансляция</a></li> </ul> <center> <iframe width="560" height="315" src="https://www.youtube.com/embed/QcPE0hh9A-Y" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe> </center> <p>Добро пожаловать!</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2020/04/21/selenide-5.11.1/ http://ru.selenide.org/2020/04/21/selenide-5.11.1 2020-04-21T00:00:00+00:00 Вышла Selenide 5.11.0 <p>Всем привет!</p> <p>Мы выпустили <a href="https://github.com/selenide/selenide/milestone/94?closed=1">Selenide 5.11.0</a>.<br /> Это уже второй карантинный релиз Selenide. И чтобы вам не засохнуть от скуки, мы сделали парочку существенных изменений.</p> <h2 id="поменяли-поведение-shouldnot-проверок-для-несуществующего-элемента">Поменяли поведение <code class="language-plaintext highlighter-rouge">shouldNot*</code> проверок для несуществующего элемента</h2> <p>Просто взгляните на следующую таблицу, чтобы понять, что поменялось.<br /> Предположим, что элемент <code class="language-plaintext highlighter-rouge">h1</code> <strong>не найден</strong> на странице.</p> <table> <thead> <tr> <th>Проверка</th> <th>Selenide 5.10-</th> <th>Selenide 5.11+</th> </tr> </thead> <tbody> <tr> <td><code class="language-plaintext highlighter-rouge">h1.shouldNot(exist)</code></td> <td>ok</td> <td>ok</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">h1.shouldNotBe(visible)</code></td> <td>ok</td> <td>ok</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">h1.shouldBe(hidden)</code></td> <td>ok</td> <td>ok</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">h1.shouldNotHave(text("foo"))</code></td> <td>ok</td> <td>FAIL</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">h1.shouldNotHave(attribute("bar"))</code></td> <td>ok</td> <td>FAIL</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">h1.find("h2").shouldNot(exist)</code></td> <td>ok</td> <td>ok</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">h1.find("h2").shouldNotHave(text("foo"))</code></td> <td>ok</td> <td>FAIL</td> </tr> </tbody> </table> <p><br /></p> <h4 id="старая-логика">Старая логика</h4> <p>Когда-то давно в селениде было принято такое решение: проверка <code class="language-plaintext highlighter-rouge">h1.shouldNotHave(text("foo"))</code> не должна падать: нет элемента - нет и текста. Значит, условие “should not” выполнено.</p> <p>Эту логику подкрепляло и такое соображение: проверка <code class="language-plaintext highlighter-rouge">h1.shouldHave(text("foo"))</code> валится, а “shouldNot” - её отрицание, поэтому она валиться не должна.</p> <h4 id="новая-логика">Новая логика</h4> <p>Но победил прагматичный аргумент: старый алгоритм позволял слишком легко ошибиться: случайно написать неправильный локатор и не заметить, что тест ложно зелёный.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/368">issue 368</a> и <a href="https://github.com/selenide/selenide/pull/1116">PR 1116</a>.</p> <h2 id="теперь-селенид-ругается-если-slf4j-не-настроен">Теперь Селенид ругается, если SLF4J не настроен</h2> <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">IllegalStateException</span><span class="o">:</span> <span class="no">SLF4J</span> <span class="n">is</span> <span class="n">not</span> <span class="n">configured</span><span class="o">.</span> <span class="nc">You</span> <span class="n">will</span> <span class="n">not</span> <span class="n">see</span> <span class="n">any</span> <span class="nc">Selenide</span> <span class="n">logs</span><span class="o">.</span> <span class="nc">Please</span> <span class="n">add</span> <span class="n">slf4j</span><span class="o">-</span><span class="n">simple</span><span class="o">.</span><span class="na">jar</span><span class="o">,</span> <span class="n">slf4j</span><span class="o">-</span><span class="n">log4j12</span><span class="o">.</span><span class="na">jar</span> <span class="n">or</span> <span class="n">logback</span><span class="o">-</span><span class="n">classic</span><span class="o">.</span><span class="na">jar</span> <span class="n">to</span> <span class="n">your</span> <span class="n">classpath</span><span class="o">.</span> <span class="nc">See</span> <span class="nl">https:</span><span class="c1">//github.com/selenide/selenide/wiki/slf4j</span> </code></pre></div></div> <p>то не пугайтесь - просто сделайте, что там сказано. Это очень просто.</p> <h4 id="какую-проблему-мы-решали">Какую проблему мы решали?</h4> <p>Проблема в том, что если у вас в проекте не была подключена никакая реализация SLF4J, то вы могли не увидеть какие-то важные логи селенида, в т.ч. “текстовой отчёт”. Теперь вам придётся подключить какую-нибудь реализацию SLF4J.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1114">issue 1114</a> и <a href="https://github.com/selenide/selenide/pull/1115">PR 1115</a>.</p> <h2 id="добавили-метод-для-частичной-проверки-атрибута">Добавили метод для частичной проверки атрибута</h2> <p>До сих пор в селениде были методы для проверки</p> <ol> <li>наличия атрибута, и</li> <li>точного значения атрибута:</li> </ol> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"#domain-container"</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">"class"</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">"#domain-container"</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">"class"</span><span class="o">,</span> <span class="s">"container"</span><span class="o">));</span> </code></pre></div></div> <p>Теперь мы добавили метод <code class="language-plaintext highlighter-rouge">attributeMatching</code> для проверки <em>частичного</em> значения атрибута.<br /> См. примеры <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/AttributeTest.java">в тестах</a>:</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">canVerifyAttributeMatching</span><span class="o">()</span> <span class="o">{</span> <span class="err">$</span><span class="o">(</span><span class="s">"#domain-container"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">attributeMatching</span><span class="o">(</span><span class="s">"class"</span><span class="o">,</span> <span class="s">"contain.*"</span><span class="o">));</span> <span class="c1">// class="container"</span> <span class="err">$</span><span class="o">(</span><span class="s">"#domain-container"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">attributeMatching</span><span class="o">(</span><span class="s">"class"</span><span class="o">,</span> <span class="s">".*tainer"</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">"#domain-container"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">attributeMatching</span><span class="o">(</span><span class="s">"class"</span><span class="o">,</span> <span class="s">".+tain.+"</span><span class="o">));</span> <span class="o">}</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/996">issue 996</a>.<br /> Спасибо <a href="https://github.com/dstekanov">Dmytro Stekanov</a> за <a href="https://github.com/selenide/selenide/pull/1100">PR 1100</a>.</p> <h2 id="добавили-метод-для-получения-последнего-скриншота">Добавили метод для получения последнего скриншота</h2> <p>Добавили два новых метода:</p> <ul> <li><code class="language-plaintext highlighter-rouge">Screenshots.getLastThreadScreenshot()</code> - возвращает последний скриншот, сделанный селенидом в текущем потоке</li> <li><code class="language-plaintext highlighter-rouge">Screenshots.getThreadScreenshots()</code> - возвращает все скриншоты, сделанные селенидом в текущем потоке</li> </ul> <p>Обычным пользователям <strong>эти методы ни к чему</strong>: селенид и так добавляет информацию о скриншоте к сообщению об ошибке.<br /> Но эти новые методы могут быть полезны тем, кто пишет какие-нибудь свои фреймворки на основе селенида или интегрирует селенид с фреймворками типа Аллюра.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1029">issue 1029</a>.<br /> Спасибо <a href="https://github.com/dstekanov">Dmytro Stekanov</a> за <a href="https://github.com/selenide/selenide/pull/1125">PR 1125</a>.</p> <h2 id="добавили-аннотацию-checkreturnvalue-к-большинству-публичных-методов-селенида">Добавили аннотацию <code class="language-plaintext highlighter-rouge">@CheckReturnValue</code> к большинству публичных методов селенида</h2> <p>Это позволит IDE (как минимум Intellij IDEA) лучше анализировать код ваших тестов и предупреждать, если вы вызвали какой-нибудь селенидовский метод, но забыли проверить результат:</p> <center> <img src="/images/2020/04/idea-warning.png" width="500" /> </center> <p>Спасибо <a href="https://github.com/jreznot">Yuriy Artamonov</a> за <a href="https://github.com/selenide/selenide/pull/1106">PR 1106</a>.</p> <h2 id="добавили-нехватающий-метод-selectorsbytagname">Добавили нехватающий метод <code class="language-plaintext highlighter-rouge">Selectors.byTagName()</code></h2> <p>Просто чтобы было консистентно с <code class="language-plaintext highlighter-rouge">By</code>.</p> <p>Спасибо <a href="https://github.com/jreznot">Yuriy Artamonov</a> за <a href="https://github.com/selenide/selenide/pull/1104">PR 1104</a>.</p> <h2 id="исправили-url-скриншота">Исправили URL скриншота</h2> <p>… когда проект запускается на дженкинсе, и в имени проекта есть пробел.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1072">issue 1072</a>.<br /> Спасибо <a href="https://github.com/dstekanov">Dmytro Stekanov</a> за <a href="https://github.com/selenide/selenide/pull/1098">PR 1098</a>.</p> <h2 id="отключили-предупреждение-о-расширениях-в-chrome">Отключили предупреждение о расширениях в Chrome</h2> <p>Честно говоря, я так и не понял, при каких условиях это предупреждение появляется - лично я его не видел:</p> <center> <img src="/images/2020/04/chrome-warning.png" width="300" /> </center> <p>Но некоторые товарищи жаловались. Теперь мы его отключили вот такой настройкой:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">options</span><span class="o">.</span><span class="na">setExperimentalOption</span><span class="o">(</span><span class="s">"excludeSwitches"</span><span class="o">,</span> <span class="k">new</span> <span class="nc">String</span><span class="o">[]{</span><span class="s">"enable-automation"</span><span class="o">,</span> <span class="s">"load-extension"</span><span class="o">});</span> </code></pre></div></div> <p>Дайте знать, если у вас это вызовет какие-то проблемы.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1119">issue 1119</a> и <a href="https://github.com/selenide/selenide/pull/1120">PR 1120</a>.</p> <h2 id="теперь-можно-установить-selectormode-и-assertionmode-через-системные-свойства">Теперь можно установить <code class="language-plaintext highlighter-rouge">selectorMode</code> и <code class="language-plaintext highlighter-rouge">assertionMode</code> через системные свойства</h2> <p>Никто этого не просил - просто для консистентности.</p> <p>См. <a href="https://github.com/selenide/selenide/commit/231597eb6229e">коммит 231597eb6229e</a>.</p> <h2 id="метод-getwrappedelement-больше-ничего-не-ждёт">Метод <code class="language-plaintext highlighter-rouge">$.getWrappedElement()</code> больше ничего не ждёт</h2> <p>Подозреваю, что большинство из вас не знали о существовании этого метода и тем более не использовали его.<br /> Его идея была в том, чтобы дать автору теста доступ к оригинальному селениумовскому <code class="language-plaintext highlighter-rouge">WebElement</code> без всякой селенидовской магии (ну мало ли кому-то понадобится). А <a href="https://github.com/yashaka">Iakiv Kramarenko</a> заметил, что без селенидовской магии не обошлось: метод <code class="language-plaintext highlighter-rouge">$.getWrappedElement()</code> всё-таки ждал появления элемента.</p> <p>Теперь он больше ничего не ждёт. Если элемента нет - он сразу кидает селениумовский <code class="language-plaintext highlighter-rouge">org.openqa.selenium.NoSuchElementException</code>. Ну и легендарный <code class="language-plaintext highlighter-rouge">StaleElementReferenceException</code> вы тоже можете отхватить, конечно (ну мало ли кому-то захочется вспомнить молодость).</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1015">issue 1015</a> и <a href="https://github.com/selenide/selenide/pull/1124">PR 1124</a>.</p> <h2 id="статистика">Статистика</h2> <p>И моё любимое: статистика скачиваний селенида. Мы пробили потолок в 130 тысяч в месяц!</p> <center> <img src="/images/2020/04/selenide.downloads.png" width="800" /> </center> <p><br /> и 23 тысячи уникальных айпишников:</p> <center> <img src="/images/2020/04/selenide.unique-ips.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/2020/04/19/selenide-5.11.0/ http://ru.selenide.org/2020/04/19/selenide-5.11.0 2020-04-19T00:00:00+00:00 Вышла Selenide 5.10.0 <p>Здоровендос!</p> <p>Шёл третий день карантина.</p> <p>Чтобы вам не было одиноко, мы выпустили <a href="https://github.com/selenide/selenide/milestone/93?closed=1">Selenide 5.10.0</a> с кучей улучшений, некоторые из которых даже окажутся капельку обратно несовместимыми. Ну, чтобы вы не скучали в своих берлогах.</p> <ul class="blogpost-menu"> <li><a href="#add-shadow-dom-support">Добавили поддержку Shadow DOM</a></li> <li><a href="#exclude-bup-by-default">не тянем BrowserUpProxy по умолчанию</a></li> <li><a href="#replace-guava">Поменяли Guava API на Java API</a></li> <li><a href="#add-quotes-to-report">Селенидовский отчёт в Allure красивее</a></li> <li><a href="#add-image-condition">Добавили условие shouldBe(image)</a></li> <li><a href="#video">Видосики</a></li> </ul> <h2 id="add-shadow-dom-support">Добавили поддержку Shadow DOM</h2> <p>См. примеры <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/ShadowElementTest.java">в тестах</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">"#anyButton"</span><span class="o">,</span> <span class="s">"#shadow-host"</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">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="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Inside Shadow-DOM"</span><span class="o">));</span> <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="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><em>Firefox</em>: Вызов <code class="language-plaintext highlighter-rouge">setValue("test")</code> / <code class="language-plaintext highlighter-rouge">val("text")</code> на input элементе выкидывает ошибку “not reachable by keyboard”. <br /> Как временное решение, можно использовать <code class="language-plaintext highlighter-rouge">fastSetValue=true</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">fastSetValue</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span> <span class="err">$</span><span class="o">(</span><span class="n">shadowCss</span><span class="o">(</span><span class="s">"input"</span><span class="o">,</span> <span class="s">"#shadow-host"</span><span class="o">)).</span><span class="na">setValue</span><span class="o">(</span><span class="s">"test"</span><span class="o">);</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1014">issue 1014</a>.<br /> Спасибо <a href="https://github.com/dstekanov">Dmytro Stekanov</a> за <a href="https://github.com/selenide/selenide/pull/1090">PR 1090</a>.</p> <h2 id="exclude-bup-by-default">Selenide больше не тянет BrowserUpProxy по умолчанию</h2> <p>Изначально это предложил Алексей Баранцев, так что бейте его, если что. :)</p> <p>Мы сопоставили вместе два факта:</p> <ol> <li>Селенид по умолчанию тянет за собой BrowserUpProxy и его зависимости - всего ~17 мегабайт.</li> <li>Большинство пользователей (наверное) не использует селенидовский прокси.</li> </ol> <p>и решили обрадовать Грету Тумберг и не качать эти 17 мегабайт по умолчанию.</p> <h3 id="зависимость">Зависимость</h3> <p>Те из вас, кто использует прокси, просто должны добавить в свой проект ещё одну зависимость:</p> <div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">testRuntime</span> <span class="s1">'com.browserup:browserup-proxy-core:2.0.1'</span> </code></pre></div></div> <p>(у многих из вас она и так уже есть).</p> <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">IllegalStateException</span><span class="o">:</span> <span class="nc">Cannot</span> <span class="n">initialize</span> <span class="n">proxy</span><span class="o">.</span> <span class="nc">Probably</span> <span class="n">you</span> <span class="n">should</span> <span class="n">add</span> <span class="nc">BrowserUpProxy</span> <span class="n">dependency</span> <span class="n">to</span> <span class="n">your</span> <span class="n">project</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">drivercommands</span><span class="o">.</span><span class="na">CreateDriverCommand</span><span class="o">.</span><span class="na">createDriver</span><span class="o">(</span><span class="nc">CreateDriverCommand</span><span class="o">.</span><span class="na">java</span><span class="o">:</span><span class="mi">44</span><span class="o">)</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">41</span><span class="o">)</span> <span class="n">caused</span> <span class="nl">by:</span> <span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">NoClassDefFoundError</span><span class="o">:</span> <span class="n">com</span><span class="o">/</span><span class="n">browserup</span><span class="o">/</span><span class="n">bup</span><span class="o">/</span><span class="nc">BrowserUpProxy</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1021">issue 1021</a> и <a href="https://github.com/selenide/selenide/pull/1094">PR 1094</a>.</p> <p><strong>UPD 12.03.2023</strong> В наше время больше не нужно добавлять ту зависимость <code class="language-plaintext highlighter-rouge">browserup-proxy-core</code>. Просто используйте <code class="language-plaintext highlighter-rouge">com.codeborne:selenide-proxy</code> вместо <code class="language-plaintext highlighter-rouge">com.codeborne:selenide</code>, и все нужные зависимости подтянутся автоматически.</p> <h3 id="просто-из-интереса">Просто из интереса</h3> <p>Кто же там сжирает эти 17 мегабайт, спросите вы? А вот кто.<br /> Вот полный список файлов, которые должны у вас пропасть из проекта. Список впечатляет, правда?</p> <ul> <li>animal-sniffer-annotations-1.17.jar</li> <li>barchart-udt-bundle-2.3.0.jar</li> <li>bcpkix-jdk15on-1.62.jar</li> <li>bcprov-jdk15on-1.62.jar</li> <li>browserup-proxy-core-2.0.1.jar</li> <li>browserup-proxy-mitm-2.0.1.jar</li> <li>checker-qual-2.5.2.jar</li> <li>dec-0.1.2.jar</li> <li>dnsjava-2.1.9.jar</li> <li>error_prone_annotations-2.2.0.jar</li> <li>failureaccess-1.0.1.jar</li> <li>guava-27.1-jre.jar</li> <li>jackson-annotations-2.9.9.jar</li> <li>jackson-core-2.9.9.jar</li> <li>jackson-databind-2.9.9.1.jar</li> <li>javassist-3.25.0-GA.jar</li> <li>javax.activation-api-1.2.0.jar</li> <li>jaxb-api-2.3.1.jar</li> <li>jcl-over-slf4j-1.7.28.jar</li> <li>jsr305-3.0.2.jar</li> <li>jzlib-1.1.3.jar</li> <li>listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar</li> <li>littleproxy-2.0.0-beta-5.jar</li> <li>netty-all-4.1.39.Final.jar</li> </ul> <p>Кто придумал название “animal-sniffer”? Это что вообще такое - <em>нюхальщик животных</em>? <br /></p> <h2 id="replace-guava">Поменяли Guava API на соответствующие Java API</h2> <p>Мы просто поменяли</p> <ul> <li><code class="language-plaintext highlighter-rouge">com.google.common.base.Predicate</code> из Guava</li> <li>на <code class="language-plaintext highlighter-rouge">java.util.function.Predicate</code> из Java 8</li> </ul> <p>и выкинули Guava. Guava, ты была хороша и сделала много полезного (пока не вышла Java 8). Покойся с миром.</p> <p>Если вы реализовали свои <code class="language-plaintext highlighter-rouge">CollectionCondition</code>, вам придётся метод <code class="language-plaintext highlighter-rouge">apply</code> переименовать в <code class="language-plaintext highlighter-rouge">test</code>. Это должно быть легко.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1091">issue 1091</a>.<br /> Спасибо <a href="https://github.com/wlsc">Wladimir Schmidt</a> за <a href="https://github.com/selenide/selenide/pull/1091">PR 1091</a>.</p> <p><br /></p> <h2 id="add-quotes-to-report">Сделали селенидовский отчёт в Allure чуточку красивее</h2> <p>На самом деле просто добавили кавычки вокруг селекторов.<br /> Не представляю, зачем это может понадобиться, но теперь можно копировать селекторы из аллюровского отчёта и вставлять в developer console браузера, и они будут работать.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1032">issue 1032</a>.<br /> Спасибо <a href="https://github.com/dstekanov">Dmytro Stekanov</a> за <a href="https://github.com/selenide/selenide/pull/1092">PR 1092</a>.</p> <p><br /></p> <h2 id="add-image-condition">Добавили условие <code class="language-plaintext highlighter-rouge">$("img").shouldBe(image)</code></h2> <p>Позволяет проверить, что картинка есть, она загрузилась и всё в порядке.</p> <p>См. примеры <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/ImageTest.java">в тестах</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">"#valid-image img"</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">image</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#valid-image"</span><span class="o">).</span><span class="na">shouldNotBe</span><span class="o">(</span><span class="n">image</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">shouldNotBe</span><span class="o">(</span><span class="n">image</span><span class="o">);</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/1069">issue 1069</a>.<br /> Спасибо <a href="https://github.com/dstekanov">Dmytro Stekanov</a> за <a href="https://github.com/selenide/selenide/pull/1086">PR 1086</a>.</p> <p><br /></p> <h2 id="fix-search-by-attribute-with-quotes">Исправили поиск элементов по атрибуту, который содержит кавычки</h2> <p>Я не знаю, каким надо быть извращенцем, чтобы в html атрибут запихать кавычки, но такие нашлись. А селенид оказался к этому не готов и генерировал невалидный CSS локатор. Теперь это в прошлом.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1060">issue 1060</a>.<br /> Спасибо <a href="https://github.com/denysLystopadskyy">Denys Lystopadskyy</a> за <a href="https://github.com/selenide/selenide/pull/1062">PR 1062</a>.</p> <p><br /></p> <h2 id="video">Видосики</h2> <p>Немногие задумывались об этом, но возможно, SeleniumCamp 2020 - Последняя Конференция Человечества.</p> <p>Но они ещё и последние альтруисты человечества, потому что из-за карантина они досрочно выложили <a href="https://www.youtube.com/playlist?list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe">все видео с последней конференции</a> в открытый доступ.<br /> Лечитесь, айтишники, и просвещайтесь!</p> <p>Там есть три моих доклада:</p> <ul> <li><a href="https://www.youtube.com/watch?v=6MfMtky-0q4&amp;list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe&amp;index=35">Flaky tests: The method</a></li> <li><a href="https://www.youtube.com/watch?v=RmaTYY3B-Wg&amp;list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe&amp;index=41">BOF: прошлое и будущее селенида</a></li> <li><a href="https://www.youtube.com/watch?v=4vI4Z6sE7OA&amp;list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe&amp;index=16">Тройничок: Selenide для Web, Android и iOS</a> – “Толерантные локаторы”!</li> </ul> <p>И ещё из того, что я успел заметить:</p> <ul> <li>Aleksei Tiurin - <a href="https://www.youtube.com/watch?v=uCAva5bi7IY&amp;list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe&amp;index=32">Solving the problems of Espresso Android autotests</a></li> <li>Michael Bodnarchuk - <a href="https://www.youtube.com/watch?v=yETWaC91t3w&amp;list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe&amp;index=4">Puppeteer is a new WebDriver? Secrets of flawless testing.</a></li> <li>Oleksandr Khotemskyi - <a href="https://www.youtube.com/watch?v=UzdUu9QllK0&amp;list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe&amp;index=2">WebdriverIO + Puppeteer. Double gun – double fun</a></li> <li>Sergey Pirogov - <a href="https://www.youtube.com/watch?v=lMD82Pj3Llk&amp;list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe">Test coverage myth busted</a></li> <li>Mikalai Alimenkou - <a href="https://www.youtube.com/watch?v=O0-vAiqGrVk&amp;list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe&amp;index=14">Static analysis tools as the best friend of QA</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/03/18/selenide-5.10.0/ http://ru.selenide.org/2020/03/18/selenide-5.10.0 2020-03-18T00:00:00+00:00 Вышла Selenide 5.9.0 <p>Здоровендос!</p> <p>По всему миру объявлена пандемия <a href="https://www.youtube.com/watch?v=jLG3RXECQU8">flaky тестов</a>, и мы ищем новые лекарства для борьбы с ними.</p> <p>Сегодня мы выпустили <a href="https://github.com/selenide/selenide/milestone/92?closed=1">Selenide 5.9.0</a> с одной фичей, которая может помочь справиться с моргающими тестами.</p> <h2 id="добавили-фильтр-для-скачивания-файлов-downloadfilefilter">Добавили фильтр для скачивания файлов: <code class="language-plaintext highlighter-rouge">$.download(FileFilter)</code></h2> <h4 id="проблема">Проблема</h4> <p>При скачивании файлов <em>через прокси</em> селенид может иногда скачать не тот файл.<br /> Селенид ведь как скачивает файлы: кликает на кнопку “Скачать” и перехватывает ответ сервера браузеру.</p> <p>Но иногда в этот момент между браузером и сервером могут лететь какие-нибудь левые запросы, никак не связанные со скачиванием. Например, хром решает проверить обновления. Или ваше приложение шлёт запросы в google analytics. Или просто какие-то фоновые запросы. Это создаёт плодотворную почву для появления <a href="https://www.youtube.com/watch?v=jLG3RXECQU8">flaky тестов</a>, которые у вас на машине работают, а на дженкинсе иногда падают.</p> <h4 id="решение">Решение</h4> <p>Чтобы избежать таких коллизий, теперь вы можете явно указать, какой файл вы ждёте.<br /> Из коробки есть фильтры по имени и расширению файла, но вы можете создавать свои объекты <a href="https://github.com/selenide/selenide/blob/master/src/main/java/com/codeborne/selenide/files/FileFilter.java"><code class="language-plaintext highlighter-rouge">FileFilter</code></a> с какими угодно критериями.<br /> И тогда из всех ответов сервера браузеру селенид выберет тот, который подходит под ваш фильтр.</p> <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">f1</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#downloadMe"</span><span class="o">).</span><span class="na">download</span><span class="o">(</span><span class="n">withName</span><span class="o">(</span><span class="s">"hello_world.txt"</span><span class="o">));</span> <span class="nc">File</span> <span class="n">f2</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#downloadMe"</span><span class="o">).</span><span class="na">download</span><span class="o">(</span><span class="n">withNameMatching</span><span class="o">(</span><span class="s">"hello_.\\w+\\.txt"</span><span class="o">));</span> <span class="nc">File</span> <span class="n">f3</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#downloadMe"</span><span class="o">).</span><span class="na">download</span><span class="o">(</span><span class="n">timeout</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>См. <a href="https://github.com/selenide/selenide/issues/1065">issue 1065</a> и <a href="https://github.com/selenide/selenide/pull/1080">PR 1080</a>.</p> <h2 id="исправили-ошибку-при-старте-ie-3150">Исправили ошибку при старте IE 3.150</h2> <p>См. <a href="https://github.com/selenide/selenide/issues/1061">issue 1061</a>.<br /> Спасибо <a href="https://github.com/BorisOsipov">Boris Osipov</a> за <a href="https://github.com/selenide/selenide/pull/1075">PR 1075</a>.</p> <h2 id="исправили-ошибку-при-старте-microsoft-edge">Исправили ошибку при старте Microsoft Edge</h2> <p>См. <a href="https://github.com/selenide/selenide/issues/1039">issue 1039</a>.<br /> Спасибо <a href="https://github.com/BorisOsipov">Boris Osipov</a> за <a href="https://github.com/selenide/selenide/pull/1084">PR 1084</a>.</p> <h2 id="новости">Новости</h2> <ul> <li> <p>Забавный <a href="https://twitter.com/titusfortner/status/1234862932036608001">диалог</a> получился в твиттере: контрибьютор проектов Selenium и Watir Titus Fortner признался, что видел <a href="/2015/09/23/selenide-on-seleniumconf/">мой доклад про селенид на SeleniumConf</a> и спёр оттуда несколько идей для Watir, а я признался, что некоторые вещи в селениде изначально были спёрты из Watir.</p> </li> <li>Хорошая статья <a href="https://phauer.com/2019/modern-best-practices-testing-java/">Modern Best Practices for Testing in Java</a>. Масса правильных мыслей.</li> <li>Статья <a href="https://hackernoon.com/selenide-in-test-automation-through-selenoid-in-the-docker-container-ttw320f">Selenide Test Automation: Using Selenoid in the Docker Container</a></li> <li>Статья <a href="https://medium.com/@neznajuskas/parametrized-ui-testing-with-selenide-and-junit-5-9aca75a8d62f">Parametrized UI testing with Selenide and Junit 5</a></li> <li>Некий базовый проект <a href="https://github.com/romsper/qa-automation-base/tree/kotlin-junit5-appium">qa-automation-base</a>, в котором намешаны Kotlin + Selenide/Appium + JUnit 5 + Allure + Allure EE + TestRail. <br /></li> </ul> <h2 id="статистика">Статистика</h2> <p>Ну и на десерт - статистика скачиваний селенида. Растём!</p> <center> <img src="/images/2020/03/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/2020/03/10/selenide-5.9.0/ http://ru.selenide.org/2020/03/10/selenide-5.9.0 2020-03-10T00:00:00+00:00 Вышла Selenide 5.8.0 <p>Приветос!</p> <p>Мы подбили ещё пачку пуллреквестов и выпустили <a href="https://github.com/selenide/selenide/milestone/90?closed=1">Selenide 5.8.0</a>.</p> <p>Какие же обновления нас ждут?</p> <h2 id="упростили-создание-своих-условий-с-помощью-лямбд">Упростили создание своих условий с помощью лямбд</h2> <p>В классе <code class="language-plaintext highlighter-rouge">Condition</code> появился новый метод <code class="language-plaintext highlighter-rouge">match</code>, который позволяет добавлять свои проверки, не создавая подклассов <code class="language-plaintext highlighter-rouge">Condition</code>. Ему надо просто скормить лямбду.</p> <p>См. примеры <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/ConditionsTest.java">в тестах</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">"#multirowTable"</span><span class="o">).</span><span class="na">should</span><span class="o">(</span><span class="n">match</span><span class="o">(</span><span class="s">"border=1"</span><span class="o">,</span> <span class="n">el</span> <span class="o">-&gt;</span> <span class="n">el</span><span class="o">.</span><span class="na">getAttribute</span><span class="o">(</span><span class="s">"border"</span><span class="o">).</span><span class="na">equals</span><span class="o">(</span><span class="s">"1"</span><span class="o">)));</span> </code></pre></div></div> <p>Также появились похожие методы для коллекций <code class="language-plaintext highlighter-rouge">anyMatch</code>, <code class="language-plaintext highlighter-rouge">allMatch</code> и <code class="language-plaintext highlighter-rouge">noneMatch</code>. См. примеры <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/CollectionMethodsTest.java">в тестах</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">"input"</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">anyMatch</span><span class="o">(</span><span class="s">"value==dog"</span><span class="o">,</span> <span class="n">el</span> <span class="o">-&gt;</span> <span class="n">el</span><span class="o">.</span><span class="na">getAttribute</span><span class="o">(</span><span class="s">"value"</span><span class="o">).</span><span class="na">equals</span><span class="o">(</span><span class="s">"dog"</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">shouldBe</span><span class="o">(</span><span class="n">allMatch</span><span class="o">(</span><span class="s">"value==cat"</span><span class="o">,</span> <span class="n">el</span> <span class="o">-&gt;</span> <span class="n">el</span><span class="o">.</span><span class="na">getAttribute</span><span class="o">(</span><span class="s">"value"</span><span class="o">).</span><span class="na">equals</span><span class="o">(</span><span class="s">"cat"</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">shouldBe</span><span class="o">(</span><span class="n">noneMatch</span><span class="o">(</span><span class="s">"value==bird"</span><span class="o">,</span> <span class="n">el</span> <span class="o">-&gt;</span> <span class="n">el</span><span class="o">.</span><span class="na">getAttribute</span><span class="o">(</span><span class="s">"value"</span><span class="o">).</span><span class="na">equals</span><span class="o">(</span><span class="s">"bird"</span><span class="o">)));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/662">issue 662</a>.<br /> Спасибо <a href="https://github.com/dstekanov">Dmytro Stekanov</a> за <a href="https://github.com/selenide/selenide/pull/1059">PR 1059</a>.</p> <p><br /></p> <h2 id="добавили-методы-sibling-и-preceding">Добавили методы <code class="language-plaintext highlighter-rouge">$.sibling()</code> и <code class="language-plaintext highlighter-rouge">$.preceding()</code></h2> <p>… которые позволяют найти предшественников и последователей на том же уровне DOM. Бывает нужно, когда удобных локаторов нет, а навигировать по дому хочется.</p> <p>См. примеры <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/SiblingTest.java">в тестах</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">"#multirowTableFirstRow"</span><span class="o">).</span><span class="na">sibling</span><span class="o">(</span><span class="mi">0</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">id</span><span class="o">(</span><span class="s">"multirowTableSecondRow"</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">".second_row"</span><span class="o">).</span><span class="na">parent</span><span class="o">().</span><span class="na">preceding</span><span class="o">(</span><span class="mi">0</span><span class="o">).</span><span class="na">find</span><span class="o">(</span><span class="s">"td"</span><span class="o">,</span> <span class="mi">0</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">"first_row"</span><span class="o">));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/845">issue 845</a>.<br /> Спасибо <a href="https://github.com/dstekanov">Dmytro Stekanov</a> за <a href="https://github.com/selenide/selenide/pull/1064">PR 1064</a>.</p> <p><br /></p> <h2 id="запилили-поддержку-псевдо-элементов">Запилили поддержку псевдо-элементов</h2> <p>Как многие знают, в HTML есть такие штуковины как псевдо-элементы: “:before”, “:after”, “:first-letter”, “:first-line”, “:selection”. Они могут содержать важный текст и стили, которые иногда важно протестировать. Теперь вы можете это сделать.</p> <p>См. примеры <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/PseudoTest.java">в тестах</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">"h1"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">pseudo</span><span class="o">(</span><span class="s">":first-letter"</span><span class="o">,</span> <span class="s">"color"</span><span class="o">,</span> <span class="s">"rgb(255, 0, 0)"</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">"abbr"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">pseudo</span><span class="o">(</span><span class="s">":before"</span><span class="o">,</span> <span class="s">"content"</span><span class="o">,</span> <span class="s">"\"beforeContent\""</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">"abbr"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">pseudo</span><span class="o">(</span><span class="s">":before"</span><span class="o">,</span> <span class="s">"\"beforeContent\""</span><span class="o">));</span> </code></pre></div></div> <p>А также можно спросить и <code class="language-plaintext highlighter-rouge">SelenideElement</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">"h1"</span><span class="o">).</span><span class="na">pseudo</span><span class="o">(</span><span class="s">":first-letter"</span><span class="o">,</span> <span class="s">"color"</span><span class="o">)).</span><span class="na">isEqualTo</span><span class="o">(</span><span class="s">"rgb(255, 0, 0)"</span><span class="o">);</span> <span class="n">assertThat</span><span class="o">(</span><span class="err">$</span><span class="o">(</span><span class="s">"abbr"</span><span class="o">).</span><span class="na">pseudo</span><span class="o">(</span><span class="s">":before"</span><span class="o">)).</span><span class="na">isEqualTo</span><span class="o">(</span><span class="s">"\"beforeContent\""</span><span class="o">);</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/994">issue 994</a>.<br /> Спасибо <a href="https://github.com/Denysss">Denys Shynkarenko</a> за <a href="https://github.com/selenide/selenide/pull/1045">PR 1045</a>.</p> <p><br /></p> <h2 id="исправили-softassertionsextension-для-junit5">Исправили SoftAssertionsExtension для JUnit5</h2> <p>Если один из тестов падал, он помечал и все последующие тесты красным. Упс.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1071">issue 1071</a>.<br /> Спасибо <a href="https://github.com/vinogradoff">Alexei Vinogradov</a> за <a href="https://github.com/selenide/selenide/commit/e92b250337a36a7225d6fcbdffecbf102f4592da">исправление</a>.</p> <p><br /></p> <h2 id="теперь-click-кликает-всегда-в-центр-элемента">Теперь <code class="language-plaintext highlighter-rouge">$.click()</code> кликает всегда в ЦЕНТР элемента</h2> <p>В общем, история такая. Метод <code class="language-plaintext highlighter-rouge">$.click()</code> обычно кликал в центр элемента, НО если у вас проставлена настройка <code class="language-plaintext highlighter-rouge">Configuration.clickViaJS=true</code>, он кликал в левый верхний угол. Не то чтобы это было принципиально важно, но мало ли… Теперь он всегда кликает по центру. На всякий случай. Чтобы всегда всё вело себя одинаково.</p> <p>См. <a href="https://github.com/selenide/selenide/commit/106c53941c7188c5a19677ad45fbdea910960c73">коммит 106c53941c718</a>.</p> <p><br /></p> <h2 id="новости">Новости</h2> <ul> <li> <p>Представляете, доклад Алексея Виноградова <a href="https://youtu.be/3J6mX98TSjk">Selenide: Брандашмыг — интерактивное путешествие по дорогам библиотеки</a> занял 3 место в <a href="https://habr.com/ru/company/jugru/blog/489310/">ТОП-10 докладов Heisenbug 2019 Moscow</a>. Это успех!</p> </li> <li>Ничего себе! John C. Pratt создал <a href="https://chrome.google.com/webstore/detail/selenide-exporter-for-kat/mkbfcgpbkcaieiajhllpdocjfnfcbmlm">экспортер в Selenide для Katalon Recorder</a> (работает с <a href="https://chrome.google.com/webstore/detail/katalon-recorder-selenium/ljdobmomdgdljniojadhoplhkpialdid">Katalon Recorder</a>). Это дикий успех!</li> <li>Обнаружен <a href="https://github.com/razielsd/phpSelenide">phpSelenide</a> - порт Селенида на PHP. Это усPHPех!</li> <li>И если кто ещё не видел, <a href="https://github.com/automician/selenejs">SeleneJS</a> - порт Селенида на JS. Это уех!</li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2020/02/28/selenide-5.8.0/ http://ru.selenide.org/2020/02/28/selenide-5.8.0 2020-02-28T00:00:00+00:00 Вышла Selenide 5.7.0 <p>Приветос!</p> <p>Неожиданно нас завалили пуллреквестами с кучей полезных изменений. В этом сила опенсорса!</p> <p>Мы подбили всё это в кучу и выпустили <a href="https://github.com/selenide/selenide/milestone/89?closed=1">Selenide 5.7.0</a>.</p> <h2 id="мы-добавили-новую-настройку-configurationdownloadsfolder">Мы добавили новую настройку <code class="language-plaintext highlighter-rouge">Configuration.downloadsFolder</code></h2> <p>Раньше файлы скачивались в папку <code class="language-plaintext highlighter-rouge">build/reports</code> - в ту самую, где генерируются отчёты о прохождении тестов.<br /> А людям иногда хочется разделять (и властвовать?).<br /> Для них мы сделали отдельную настройку <code class="language-plaintext highlighter-rouge">Configuration.downloadsFolder</code> - именно туда теперь будут сохраняться файлы.</p> <p>По умолчанию это папка <code class="language-plaintext highlighter-rouge">build/downloads</code>.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1025">issue 1025</a>.<br /> Спасибо <a href="https://github.com/dstekanov">Dmytro Stekanov</a> за <a href="https://github.com/selenide/selenide/pull/1041">PR 1041</a>.</p> <p><br /></p> <h3 id="скачиваем-файлы-в-configurationdownloadsfolder-вместо-downloads">Скачиваем файлы в <code class="language-plaintext highlighter-rouge">Configuration.downloadsFolder</code> вместо <code class="language-plaintext highlighter-rouge">~/Downloads</code></h3> <p>Со скачиваниями файлов через прокси (<code class="language-plaintext highlighter-rouge">Configuration.fileDownload=PROXY</code>) есть ещё одна особенность.<br /> Селенид-то свои файлы скачивает в <code class="language-plaintext highlighter-rouge">build/reports</code> (а теперь в <code class="language-plaintext highlighter-rouge">build/downloads</code>), но сам-то браузер тоже скачивает свою копию файла в папку <code class="language-plaintext highlighter-rouge">~/Downloads</code> (или что там у него по умолчанию). Во-первых, тратится лишнее место на диске, а во-вторых, оттуда эти файлы никто автоматически не подчищает.</p> <p>Теперь селенид изначально открывает браузер с такими настройками, чтобы он сразу скачивал файлы в папку <code class="language-plaintext highlighter-rouge">build/downloads</code>.</p> <ol> <li>Правда, пока только Chrome и Firefox.</li> <li>И только в случае, когда селенид сам открывает браузер.</li> </ol> <p>См. <a href="https://github.com/selenide/selenide/issues/1057">issue 1057</a>. Спасибо <a href="https://github.com/dkorobtsov">Dmitri Korobtsov</a> за ревью <a href="https://github.com/selenide/selenide/pull/1058">PR 1058</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="n">switchTo</span><span class="o">().</span><span class="na">window</span><span class="o">(</span><span class="mi">3</span><span class="o">);</span> </code></pre></div></div> <p>И этот метод даже настолько умный, что ждёт, пока окно появится. Но для него невозможно было задать таймаут: пресловутые 4 секунды использовались и здесь.</p> <p>Теперь мы добавили новый метод, в котором вторым аргументом можно задать таймаут для загрузки нового окна:</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">window</span><span class="o">(</span><span class="mi">3</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">switchTo</span><span class="o">().</span><span class="na">window</span><span class="o">(</span><span class="mi">3</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">16000</span><span class="o">));</span> </code></pre></div></div> <p>См. <a href="https://github.com/selenide/selenide/issues/399">issue 399</a>.<br /> Спасибо <a href="https://github.com/dstekanov">Dmytro Stekanov</a> за <a href="https://github.com/selenide/selenide/pull/1054">PR 1054</a>.</p> <p><br /></p> <h3 id="добавили-логирование-атрибута-readonly">Добавили логирование атрибута “readonly”</h3> <p>См. <a href="https://github.com/selenide/selenide/issues/990">issue 990</a>.<br /> Спасибо <a href="https://github.com/dstekanov">Dmytro Stekanov</a> за <a href="https://github.com/selenide/selenide/pull/1042">PR 1042</a>.</p> <p><br /></p> <h3 id="исправили-ошибку-indexoutofboundsexception">Исправили ошибку IndexOutOfBoundsException</h3> <p>… при поиске первого/последнего элемента пустой коллекции</p> <p>См. <a href="https://github.com/selenide/selenide/issues/991">issue 991</a>.<br /> Спасибо <a href="https://github.com/dstekanov">Dmytro Stekanov</a> за <a href="https://github.com/selenide/selenide/pull/1043">PR 1043</a>.</p> <p><br /></p> <h3 id="и-целая-пачка-улучшений-скриншотов">И целая пачка улучшений скриншотов</h3> <h4 id="1-вернули-потерянные-скриншоты-в-screenshotsgetlastscreenshot">1. Вернули потерянные скриншоты в <code class="language-plaintext highlighter-rouge">Screenshots.getLastScreenshot()</code></h4> <p>См. <a href="https://github.com/selenide/selenide/issues/814">issue 814</a> и <a href="https://github.com/selenide/selenide/issues/880">issue 880</a>. <br /> Спасибо <a href="https://github.com/petroOv-PDFfiller">Petro Ovcharenko</a> за <a href="https://github.com/selenide/selenide/pull/1052">PR 1052</a>.</p> <p><br /></p> <h4 id="2-исправили-ссылки-на-скриншоты-в-jenkins">2. Исправили ссылки на скриншоты в Jenkins</h4> <p>Теперь селенид умеет читать переменную среды (env variable) <code class="language-plaintext highlighter-rouge">BUILD_URL</code>, и вам больше не нужно прописывать <code class="language-plaintext highlighter-rouge">BUILD_URL</code> в system properties в ваших билд-скриптах.</p> <p>Спасибо <a href="https://github.com/GongYi">GongYi</a> за <a href="https://github.com/selenide/selenide/pull/1049">PR 1049</a>.</p> <p><br /></p> <h4 id="3-исправили-ссылки-на-скриншоты-в-jenkins-для-мультимодульных-проектов-maven">3. Исправили ссылки на скриншоты в Jenkins для мультимодульных проектов Maven</h4> <p>Спасибо <a href="https://github.com/GongYi">GongYi</a> за <a href="https://github.com/selenide/selenide/pull/1049">PR 1049</a>.</p> <p><br /></p> <h3 id="обновились-на-webdrivermanager-381">Обновились на WebDriverManager 3.8.1</h3> <p>См. <a href="https://github.com/bonigarcia/webdrivermanager/compare/webdrivermanager-3.8.1...master">changelog</a> (в т.ч. поддержка Edge 80).</p> <p><br /> <br /></p> <h1 id="мероприятия">Мероприятия</h1> <h3 id="seleniumcamp-2020">SeleniumCamp 2020</h3> <p>Приезжайте в Киев 21-22 февраля на конференцию <a href="https://seleniumcamp.com/program/">SeleniumCamp</a>! <br /> Я буду выступать с двумя докладами:</p> <ul> <li><a href="https://seleniumcamp.com/talk/flaky-tests-method/">Flaky tests: МЕТОД</a></li> <li><a href="https://seleniumcamp.com/talk/selenide-for-web-android-and-ios/">Тройничок: Selenide для Web, Android и iOS</a></li> </ul> <p>и ещё будет неформальная сессия BOF <a href="https://seleniumcamp.com/talk/bof-glorious-past-and-promising-future-of-selenide/">про дальнейшие планы развития Селенида</a>.</p> <h3 id="митап-про-селенид-в-германии">Митап про Селенид в Германии</h3> <p>Какие-то черти запилили <a href="https://stugrm.de/stugrm-meetups/">митап про Селенид</a> в Германии 12 февраля.<br /> Приятно, чо.</p> <h3 id="статистика">Статистика</h3> <p>Количество скачиваний селенида за год выросло в 2.5 раза с 40 тысяч до 110 тысяч.</p> <center> <img src="/images/2020/02/selenide.downloads.png" width="800" /> </center> <p><br /></p> <p>А количество уникальных айпишников перевалило за 20 тысяч:</p> <center> <img src="/images/2020/02/selenide.unique-ips.png" width="800" /> </center> <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/2020/02/07/selenide-5.7.0/ http://ru.selenide.org/2020/02/07/selenide-5.7.0 2020-02-07T00:00:00+00:00 Вышла Selenide 5.6.1 <p>Всех с Новым Годом!</p> <p>Новый год - новый релиз. Встречайте <a href="https://github.com/selenide/selenide/milestone/88?closed=1">Selenide 5.6.1</a>.</p> <h1 id="добавили-метод-selenideexecuteasyncscript">Добавили метод <code class="language-plaintext highlighter-rouge">Selenide.executeAsyncScript()</code></h1> <p>Нет такого человека, который ни разу не запускал бы метод <code class="language-plaintext highlighter-rouge">Selenide.executeJavaScript()</code>. JavaScript позволяет выйти <a href="/2019/12/24/advent-calendar-javascript-tricks/">на новый уровень сумрака</a> в автоматизации.</p> <p>А теперь мы добавили ещё и метод <code class="language-plaintext highlighter-rouge">Selenide.executeAsyncScript()</code>. Правда, я плохо представляю, в каких случаях он может понадобится, но если кому надо - теперь он есть.</p> <p>Обратите внимание, его использование сложнее, чем обычного <code class="language-plaintext highlighter-rouge">executeJavaScript()</code>. После исполнения асинхронного JS кода нужно вызвать callback с результатом. А callback нужно получить из <em>последнего</em> аргумента:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">long</span> <span class="n">value</span> <span class="o">=</span> <span class="o">(</span><span class="nc">Long</span><span class="o">)</span> <span class="nc">Selenide</span><span class="o">.</span><span class="na">executeAsyncJavaScript</span><span class="o">(</span> <span class="s">"var callback = arguments[arguments.length - 1]; "</span> <span class="o">+</span> <span class="s">"setTimeout(function() { "</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">" callback(10);"</span> <span class="o">+</span> <span class="s">"}, 5000);"</span> <span class="o">);</span> <span class="n">assertThat</span><span class="o">(</span><span class="n">value</span><span class="o">).</span><span class="na">isEqualTo</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/1030">issue 1030</a>.<br /> Спасибо <a href="https://github.com/tyge68">Thierry Ygé</a> за <a href="https://github.com/selenide/selenide/pull/1031">PR 1031</a>.</p> <p><br /></p> <h1 id="научили-selenide-скачивать-через-прокси-файлы-без-заголовка-content-disposition">Научили Selenide скачивать через прокси файлы без заголовка <code class="language-plaintext highlighter-rouge">Content-Disposition</code></h1> <p>Как вы знаете, Selenide умеет скачивать файлы через свой прокси. Но при скачивании он перехватывал только те ответы сервера, в которых присутствует заголовок <code class="language-plaintext highlighter-rouge">Content-Disposition</code> (чтобы узнать оттуда имя скачиваемого файлы).</p> <p>Как выяснилось, этот заголовок необязателен. Файлы могут скачиваться и без него.</p> <p>Теперь селенидовский прокси стал умнее.</p> <ol> <li>Прежде чем скачать файл, он ждёт, пока закончатся все предыдущие запросы-ответы между браузером и сервером.</li> <li>Кликает кнопку скачивания</li> <li>Перехватывает ВСЕ запросы-ответы между браузером и сервером (вне зависимости от заголовков).</li> <li>И пытается понять, какой из них больше всего похож на скачивание файла.</li> </ol> <p>А имя файла (в случае ответа без заголовка <code class="language-plaintext highlighter-rouge">Content-Disposition</code>) берётся просто из URL.</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1034">issue 1034</a> и <a href="https://github.com/selenide/selenide/pull/1035">PR 1035</a>.</p> <p><br /></p> <h1 id="исправили-метод-webdriverrunnerusing">Исправили метод <code class="language-plaintext highlighter-rouge">WebDriverRunner.using()</code></h1> <p>В октябре мы <a href="/2019/10/16/selenide-5.4.0/#add-method-using">добавили метод <code class="language-plaintext highlighter-rouge">using</code></a>.<br /> Судя по всему, вы ещё не успели его попробовать, потому что никто не пожаловался на багу: этот метод закрывал вебдрайвер после использования (хотя не должен). Ну вот, эту багу мы исправили.</p> <p>См. <a href="https://github.com/selenide/selenide/commit/4d1b19972d">коммит 4d1b19972d</a>.</p> <p><br /></p> <h1 id="обновились-на-webdrivermanager-380">Обновились на WebDriverManager 3.8.0</h1> <p>там было исправлено несколько ошибок, в т.ч. моего авторства :)</p> <p>См. <a href="https://github.com/bonigarcia/webdrivermanager/compare/webdrivermanager-3.8.0...master">changelog</a>.<br /> В частности, WDM теперь должен корректно работать без доступа в интернет.</p> <p><br /></p> <h2 id="новости">Новости</h2> <ul> <li>Огонь! <a href="https://vitalyzinevich.visualstudio.com/_git/Selenious">Selenious</a> - порт селенида на .NET<br /> Ребята обещали, что проект рабочий, они его в реальном проекте используют.</li> <li>Статья от LambdaTest: <a href="https://www.lambdatest.com/support/docs/selenide-tests-with-lambdatest-online-selenium-grid-for-automated-cross-browser-testing/">Selenide Tests With LambdaTest – Online Selenium Grid For Automated Cross Browser Testing</a></li> <li>Моё видео с октябрьской конференции Cyprus Quality Conference <a href="https://youtu.be/Y04rU7qV7Vg">Threesome: Selenide for Web, Android and iOS</a>. Не переживайте, в феврале я его буду рассказывать по-русски на SeleniumCamp.</li> <li>Если кто пропустил, серия постов <a href="/blog">Selenide Advent Calendar</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/01/14/selenide-5.6.1/ http://ru.selenide.org/2020/01/14/selenide-5.6.1 2020-01-14T00:00:00+00:00 Вышла Selenide 5.6.0 <p>Всем привет!</p> <p>Под конец года мы выпустили <a href="https://github.com/selenide/selenide/milestone/87?closed=1">Selenide 5.6.0</a> с одним обновлением.</p> <p>Мы поменяли <code class="language-plaintext highlighter-rouge">BrowserMobProxy</code> (который больше не поддерживается) на его форк <code class="language-plaintext highlighter-rouge">BrowserUpProxy</code> (текущая версия 2.0.1).</p> <p>См. <a href="https://github.com/selenide/selenide/issues/1019">issue 1019</a>.<br /> Спасибо <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> за <a href="https://github.com/selenide/selenide/pull/1020">PR 1020</a>.</p> <h2 id="что-хорошего-в-этом-browserupproxy">Что хорошего в этом <code class="language-plaintext highlighter-rouge">BrowserUpProxy</code>?</h2> <p>Он</p> <ul> <li>Поддерживает Brotli Compression (а не только gzip)</li> <li>Поддерживает HTTP/2</li> <li>Основан на поддерживаемом форке <a href="https://github.com/mrog/LittleProxy">LittleProxy</a></li> <li>Использует какой-то улучшенный <a href="https://github.com/sdstoehr/har-reader">HAR reader</a></li> <li>Умеет фильтровать записи в HAR</li> <li>Поддерживает версионированные заголовки для JSON типа <code class="language-plaintext highlighter-rouge">Content-Type=application/something-v1+json</code></li> <li>Имеет встроенные ассерты для сетевых запросов (что это вообще?)</li> </ul> <p>Полный список изменений <code class="language-plaintext highlighter-rouge">BrowserUpProxy</code> (по сравнению с BrowserMobProxy) есть <a href="https://github.com/browserup/browserup-proxy/blob/master/CHANGELOG.md">тут</a>.</p> <h2 id="как-нам-обновиться">Как нам обновиться?</h2> <p>В большинстве случаев вам не придётся ничего менять. Всё работает как работало. <br /> Изменения потребуются только в двух случаях:</p> <h5 id="1-если-вы-явно-импортировали-bmp-то-вам-нужно-поменять-зависимость">1. Если вы явно импортировали BMP, то вам нужно поменять зависимость</h5> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">net</span><span class="o">.</span><span class="na">lightbody</span><span class="o">.</span><span class="na">bmp</span><span class="o">:</span><span class="n">browsermob</span><span class="o">-</span><span class="nl">core:</span><span class="mf">2.1</span><span class="o">.</span><span class="mi">5</span> </code></pre></div></div> <p>на</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">com</span><span class="o">.</span><span class="na">browserup</span><span class="o">:</span><span class="n">browserup</span><span class="o">-</span><span class="n">proxy</span><span class="o">-</span><span class="nl">core:</span><span class="mf">2.0</span><span class="o">.</span><span class="mi">1</span> </code></pre></div></div> <h5 id="2-если-вы-определяли-requestfilter-или-responsefilter">2. Если вы определяли <code class="language-plaintext highlighter-rouge">RequestFilter</code> или <code class="language-plaintext highlighter-rouge">ResponseFilter</code>,</h5> <p>то вам придётся поменять импорт</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">net.lightbody.bmp.*</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">com.browserup.bup.*</span><span class="o">;</span> </code></pre></div></div> <p>И всё.</p> <p><br /></p> <h2 id="новости">Новости</h2> <p>Завезли видео с сентябрьской конференции QA Fest:</p> <ul> <li><a href="https://www.youtube.com/watch?v=be_cTwayRQc">Андрей Солнцев. Selenide для профи</a></li> <li><a href="https://www.youtube.com/watch?v=pln38fIbYqA&amp;t=226s">Андрей Солнцев. Десять причин моей ненависти</a></li> <li>И остальные <a href="https://www.youtube.com/playlist?list=PLuOBDBq7MW70q24thB9tidD2-2Tysf8FS">видео QA Fest 2019</a></li> <li>Гугловская статья про <a href="https://testing.googleblog.com/2019/12/testing-on-toilet-tests-too-dry-make.html">принципы DAMP и DRY</a></li> <li>Ещё один фреймворк на базе Selenide: <a href="https://www.justtestlah.qa/">JustTestLah! (JTL)</a> - Помесь BDD, Selenide, Appium для Android, iOS и Web</li> <li>Если кто пропустил, серия постов <a href="/blog">Selenide Advent Calendar</a></li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2019/12/26/selenide-5.6.0/ http://ru.selenide.org/2019/12/26/selenide-5.6.0 2019-12-26T00:00:00+00:00 Трюки с JavaScript <p>Привет!</p> <p>На дворе 24 декабря, католическое рождество. А это значит, что Advent Calendar подошёл к концу.</p> <p>И напоследок мы поиграемся с JavaScript.</p> <p>Как язык JavaScript, конечно, дно, но он даёт большие возможности при написании автотестов.<br /> Он позволяет залезть в такие дыры, куда с обычным вебдрайвером и не снилось.</p> <p>Приведу несколько примеров из реальных проектов.</p> <h2 id="выбрать-дату">Выбрать дату</h2> <p>Есть масса всевозможных элементов для выбора даты - т.н. “date picker”. И выбрать в них нужную дату - это вечная головная боль.</p> <p>Если реализовывать такой метод в лоб:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Test</span> <span class="o">{</span> <span class="n">setDateByName</span><span class="o">(</span><span class="s">"recurrent.startDate"</span><span class="o">,</span> <span class="s">"16.01.2009"</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>Придётся сделать примерно следующие шаги:</p> <ol> <li>Тыкнуть иконку “календарик”</li> <li>Тыкнуть год</li> <li>Тыкнуть стрелку “месяц назад” (сколько раз?)</li> <li>Тыкнуть день</li> <li>Ой, фсё, сегодня 29 февраля. Тест упал.</li> </ol> <p><strong>Долго, сложно, ненадёжно.</strong></p> <p><br /></p> <h4 id="а-вот-как-этот-метод-можно-реализовать-с-помощью-js">А вот как этот метод можно реализовать с помощью JS:</h4> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">setDateByName</span><span class="o">(</span><span class="nc">String</span> <span class="n">name</span><span class="o">,</span> <span class="nc">String</span> <span class="n">date</span><span class="o">)</span> <span class="o">{</span> <span class="n">executeJavaScript</span><span class="o">(</span> <span class="nc">String</span><span class="o">.</span><span class="na">format</span><span class="o">(</span><span class="s">"$('[name=\"%s\"]').val('%s')"</span><span class="o">,</span> <span class="n">name</span><span class="o">,</span> <span class="n">date</span><span class="o">)</span> <span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p><strong>Быстро и надёжно.</strong></p> <p>Возможно, вам смутит, что это не совсем “честный” способ. Но об этом мы поговорим в конце. Не переключайтесь.</p> <h2 id="спрятать-календарик">Спрятать календарик</h2> <p>Допустим, календарик всё же открылся. Как его спрятать? Решение в лоб - тыкнуть крестик в углу. Опять же, это медленно и ненадёжно:</p> <ul> <li>крестик вечно располагается в разных углах</li> <li>расположение крестика часто меняется в зависимости от дизайна, размера страницы и т.п.</li> <li>иногда календарик открывается не сразу - нужно добавить ожидание на открытие, чтобы тут же закрыть.</li> </ul> <p>Идиотская ситуация.</p> <p><br /></p> <h4 id="а-вот-как-этот-метод-можно-реализовать-с-помощью-js-1">А вот как этот метод можно реализовать с помощью JS:</h4> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">executeJavaScript</span><span class="o">(</span> <span class="s">"$('.datepicker').hide();"</span> <span class="o">);</span> </code></pre></div></div> <p><strong>Быстро и надёжно.</strong></p> <h2 id="перелистнуть-перелистывалку">Перелистнуть перелистывалку</h2> <p>Представим себе страницу, на которой есть “перелистывалка” карт. Нужно выбрать нужную карту, двигая наманикюренным пальчиком.<br /> <em>Как сэмулировать это селениумом?</em><br /> Можно, конечно. Всякие там Drag’n’Drop, Actions. Нажал, потянул, отпустил. Но всё это <strong>медленно и нестабильно</strong>.<br /> Это легко может сломаться от малейших изменений дизайна, изменения размерна окна браузера, потери фокуса и т.д.</p> <h4 id="а-вот-как-можно-с-помощью-js">А вот как можно с помощью JS:</h4> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">selectAccount</span><span class="o">(</span><span class="nc">String</span> <span class="n">accountId</span><span class="o">)</span> <span class="o">{</span> <span class="n">executeJavaScript</span><span class="o">(</span> <span class="nc">String</span><span class="o">.</span><span class="na">format</span><span class="o">(</span><span class="s">"$('[data-account-id=\"%s\"]').attr('data-card-account', 'true')"</span><span class="o">,</span> <span class="n">accountId</span><span class="o">)</span> <span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>Это нетривиально. Пришлось поизучать код этой “перелистывалки” и понять, какой JS код она дёргает при перелистывании.<br /> И дёрнуть из теста аналогичный JS код. Придётся поработать головой, но зато это <strong>быстро и надёжно.</strong></p> <h2 id="выбрать-опцию-в-bootstrap-select">Выбрать опцию в bootstrap select</h2> <p>Многие UI фреймворки заменяют стандартный <code class="language-plaintext highlighter-rouge">&lt;select&gt;</code> на какие-то свои самодельные супер-пупер красивые/динамичные/удобные элементы, сварганенные из нагромождения <code class="language-plaintext highlighter-rouge">&lt;div&gt;</code>, <code class="language-plaintext highlighter-rouge">&lt;span&gt;</code>, <code class="language-plaintext highlighter-rouge">&lt;li&gt;</code> и т.п. с кучей разных CSS-классов и стилей. Для автоматизатора это всегда боль.</p> <p>Один из таких фреймворков - Bootstrap. И в нём тоже есть свой <code class="language-plaintext highlighter-rouge">&lt;select&gt;</code>. Мы долго пытались научиться выбирать из него значения: тыкали на один div, ждали появления следующего span, тыкали на него, искали нужный div с правильными атрибутами… Всё это работало долго и часто падало на дженкинсе. Причин падения так до конца и не удалось понять. Хотя мы честно пытались.</p> <p>В итоге мы реализовали метод</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Test</span> <span class="o">{</span> <span class="n">selectBootstrap</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">"operationCode"</span><span class="o">)),</span> <span class="s">"11100"</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>с помощью JavaScript:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">selectBootstrap</span><span class="o">(</span><span class="nc">WebElement</span> <span class="n">select</span><span class="o">,</span> <span class="nc">String</span> <span class="n">value</span><span class="o">)</span> <span class="o">{</span> <span class="n">executeJavaScript</span><span class="o">(</span> <span class="s">"$(arguments[0]).val(arguments[1]).trigger('change')"</span><span class="o">,</span> <span class="n">select</span><span class="o">,</span> <span class="n">value</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p><strong>Быстро и надёжно.</strong></p> <p>А с помощью <a href="https://ru.selenide.org/2019/09/02/selenide-5.3.0/">метода <code class="language-plaintext highlighter-rouge">execute</code></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="nc">By</span><span class="o">.</span><span class="na">name</span><span class="o">(</span><span class="s">"operationCode"</span><span class="o">)).</span><span class="na">execute</span><span class="o">(</span><span class="n">selectBootstrap</span><span class="o">(</span><span class="s">"11100"</span><span class="o">));</span> </code></pre></div></div> <h2 id="слайдер">Слайдер</h2> <p>На странице слайдер. Можно таскать ползунок туда-сюда от 0 до 100.<br /> Как это сделать в тесте?</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Test</span> <span class="o">{</span> <span class="n">setMaxYearlyFee</span><span class="o">(</span><span class="mi">100</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>Тут даже классический Drag’n’Drop не поможет, потому что нет целевого элемента, куда перетаскивать.<br /> Снова Actions, снова нажал-потянул-отпустил (по координатам?), снова <strong>медленно и нестабильно</strong>.</p> <h4 id="а-можно-с-помощью-js">А можно с помощью JS:</h4> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">setMaxYearlyFee</span><span class="o">(</span><span class="kt">int</span> <span class="n">value</span><span class="o">)</span> <span class="o">{</span> <span class="n">executeJavaScript</span><span class="o">(</span> <span class="s">"$('#sld').data('slider').value[0] = arguments[0];"</span> <span class="o">+</span> <span class="s">"$('#sld').triggerHandler('slide');"</span><span class="o">,</span> <span class="n">value</span> <span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>Снова пришлось поковыряться в коде, чтобы узнать, какой JS код дёргает слайдер. Зато работает. Зато <strong>быстро и надёжно.</strong></p> <h2 id="заигнорить-чёртов-confirm">Заигнорить чёртов confirm</h2> <p>В Selenide есть удобные методы, чтобы нажать “Ok” или “Cancel” в модальном диалоге <code class="language-plaintext highlighter-rouge">alert</code>, <code class="language-plaintext highlighter-rouge">prompt</code> или <code class="language-plaintext highlighter-rouge">confirm</code>.<br /> Но с этими модальными окошками периодически возникает проблемы. Иногда они почему-то не закрываются, и после этого вебдрайвер не может ничего сделать с браузером, в том числе снять скриншот. Подробнее об этом я рассказывал в видео <a href="https://www.youtube.com/watch?v=jLG3RXECQU8">Flaky tests</a>.</p> <h4 id="и-снова-на-помощь-приходит-javascript">И снова на помощь приходит JavaScript!</h4> <p>Вот так можно “типа нажать Ok” в любом <code class="language-plaintext highlighter-rouge">confirm</code> диалоге:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kt">void</span> <span class="nf">mockConfirm</span><span class="o">()</span> <span class="o">{</span> <span class="n">executeJavaScript</span><span class="o">(</span> <span class="s">"window.confirm = function() {return true;};"</span> <span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <h2 id="плагины-cordova">Плагины Cordova</h2> <p>В одном проекте мы писали гибридное мобильное приложение с помощью фреймворка Cordova.<br /> Он создаёт такое приложение, в котором очень маленькая нативная часть запускает браузер (т.н. WebView), а в нём уже открывает веб-приложение. А доступ к нативным функциями мобильника (контакты, телефон, геолокация и пр.) предоставляет в виде JavaScript-плагинов.</p> <p>Это очень удобно для тестирования. Для запуска автотестов не нужны реальные мобильники, достаточно открыть урл в обычном браузере (можно ещё и в режиме <a href="https://ru.selenide.org/2019/11/29/selenide-5.5.1/">эмуляции мобильника</a> - вообще не отличишь).</p> <p>Но вот как тестировать функционал, требующий доступа к нативным функциям мобильника?</p> <p>И снова на помощь приходит JS. Мы можем эмулировать плагины Cordova, управляя из теста их поведением:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Test</span> <span class="o">{</span> <span class="n">mockContactsAPI</span><span class="o">(</span><span class="s">"+79110080075"</span><span class="o">);</span> <span class="o">}</span> <span class="kd">private</span> <span class="kt">void</span> <span class="nf">mockContactsAPI</span><span class="o">(</span><span class="nc">String</span> <span class="n">number</span><span class="o">)</span> <span class="o">{</span> <span class="n">executeJavaScript</span><span class="o">(</span> <span class="s">"window.plugins = {"</span> <span class="o">+</span> <span class="s">" contactNumberPicker: { "</span> <span class="o">+</span> <span class="s">" pick: function(callback) {"</span> <span class="o">+</span> <span class="s">" callback({"</span> <span class="o">+</span> <span class="s">" phoneNumber:\""</span> <span class="o">+</span> <span class="n">number</span> <span class="o">+</span> <span class="s">"\""</span> <span class="s">" });}}}"</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>Выражение “управлять поведением” кажется диким? Тогда посмотрите видео <a href="https://www.youtube.com/watch?v=ePvrXUCeAr8">Arrange, mazafaka!</a> с конференции SeleniumCamp 2018.</p> <p>А мы имеем функцию <code class="language-plaintext highlighter-rouge">mockContactsAPI</code>, которая позволяет “типа выбрать” нужный номер из “типа адресной книги” “типа телефона”.<br /> Собственно, это единственный способ покрыть тестами все возможные случаи: и когда номер найден, и когда не найден, и когда это дубликат, и с 100500 китайскими символами и бог знает какие ещё. <strong>Быстро и надёжно.</strong></p> <h2 id="но-это-же-не-по-настоящему">Но это же не по-настоящему?</h2> <p>Я знаю, у многих из вас полыхает мысль: “Это же фейк, обман, это не по-настоящему! Тесты должны делать так же, как реальный пользователь - иначе есть риск, что тест не обнаружит реальную ошибку.”</p> <p>Понимаю.</p> <p>Но возражу.</p> <blockquote> <p>Быстрые и надёжные тесты лучше, чем “реалистичные” (но медленные и нестабильные) тесты.</p> </blockquote> <ul> <li>Если при каждом запуске треть ваших тестов падает.</li> <li>Если каждый раз вы тратите полдня на разбор упавших тестов.</li> <li>Если заставляете ручников прогонять вручную “автоматические” сценарии, чтобы убедиться, что функционал не сломан (и это было просто случайное падение).</li> <li>Если вы заполняете эксельку с результатами упавших-не-по-настоящему тестов.</li> <li>Если в компании нет доверия к тестам.</li> </ul> <p><em>То какой к чёрту прок от ваших “настоящих” тестов?</em><br /> Один вред.</p> <ul> <li>Лучше пусть мои тесты будут быстрыми и стабильными.</li> <li>И с лёгкостью проверять разные сложные случаи, которые “по-настоящему” повторить нереально.</li> <li>А я спокойно буду жить с пониманием того, что целью автоматизации никогда и не было <em>автоматизировать абсолютно всё</em>.</li> </ul> <p><br /></p> <p>Вы всё ещё хотите возразить:</p> <h3 id="и-всё-таки-моей-душе-спокойнее-когда-всё-по-настоящему">И всё-таки моей душе спокойнее, когда всё по-настоящему.</h3> <p>Спешу вас огорчить.</p> <ul> <li>Ваши “реалистичные” тесты на Selenium WebDriver по-любому <em>не настоящие</em>. Они работают не так, как реальный пользователь. Вебдрайвер формирует http-запрос на каждую вашу команду и даже - вот сюрприз! - запускает некую логику на JavaScript, чтобы определить видимость элементов и т.п.</li> <li>О да, в некотором смысле вызов действия через JavaScript даже “реалистичнее”, чем через WebDriver. Это ближе к тому, что на самом деле делает браузер.</li> <li>И даже ваши ручные тестировщики, прокликивающие ваши сценарии - <em>не настоящие!</em> Они работают не так, как реальный пользователь.</li> </ul> <p>Живите теперь с этим. :)</p> <h2 id="что-теперь">Что теперь?</h2> <p>А всё. Это был последний пост рождественского календаря. Уффф!</p> <p>Скажу честно: я всё это затеял, чтобы набить руку и приучиться много писать. Надеюсь, это поможет в <a href="https://selenide.org/selenide-site-ng/">обновлении сайта</a> и написании документации. А там, глядишь, и до книги дойдёт. :)</p> <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/2019/12/24/advent-calendar-javascript-tricks/ http://ru.selenide.org/2019/12/24/advent-calendar-javascript-tricks 2019-12-24T00:00:00+00:00 Defaŭlta lingvo <h1 id="defaŭlta-lingvo">Defaŭlta lingvo</h1> <p>Название сегодняшней темы пришло из языка Эсперанто и означает “язык по умолчанию”.</p> <p>Вы могли заметить, что некоторые веб-приложения и сайты автоматически меняют свой язык в зависимости от настроек вашего браузера или вашего местоположения.</p> <h2 id="проблема">Проблема</h2> <p>В том случае, когда у вас в команде интернационал разработчиков, которые пишут и запускают тесты на разных компьютерах, вы могли обратить внимание, что иногда одни и те же тесты начинают падать из-за того, приложение запустилось не на том языке, для которого писались тесты.</p> <p>Если приложение выбирает язык в зависимости от местоположения пользователя, то писать стабильные тесты запускающиеся в разных странах будет непросто. Зато, если приложение всего лишь смотрит в браузере на язык предпочитаемый пользователем по умолчанию, задача сильно упрощается.</p> <h2 id="решение">Решение</h2> <p>Итак, допустим у вас есть тесты, написанные для языка, другого чем тот, который является языком вашего браузера по умолчанию. Например - ваши тесты ожидают <em><strong>немецкий</strong></em>.</p> <p>Теперь у вас есть следующие опции:</p> <ul> <li>Поменяйте язык по умолчанию вашей системы. Теперь большинство ваших программ на компьютере заговорят по-немецки. <em><strong>Ordnung muss sein!</strong></em></li> <li>Поменяйте в вашем браузере порядок языков так, чтобы самым предпочитаемым стал немецкий. Сохраните профиль браузера. С помощью гугла, напильника и удачи сконфигурируйте тесты так, чтобы профиль загружался перед запуском каждого теста. Да, не забудьте удалить немецкий из топа в списке предпочитаемых языков, иначе, ну вы поняли - <em><strong>Ordnung….</strong></em></li> <li>Ну или - просто воспользуйтесь Chrome preference “intl.accept_languages” установив её значение на “de” (немецкий язык).</li> </ul> <p>Разумеется, вы можете легко сделать это в Selenide. Установите значение системной переменной <code class="language-plaintext highlighter-rouge">chromeoptions.prefs=intl.accept_languages=de</code> или в коде:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">System</span><span class="o">.</span><span class="na">setProperty</span><span class="o">(</span><span class="s">"chromeoptions.prefs"</span><span class="o">,</span><span class="s">"intl.accept_languages=de"</span><span class="o">);</span> </code></pre></div></div> <p>или, лучше, в конфигурационных файлах Maven или Gradle</p> <h3 id="maven">Maven</h3> <p>maven <code class="language-plaintext highlighter-rouge">pom.xml</code></p> <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ... <span class="nt">&lt;plugin&gt;</span> <span class="nt">&lt;artifactId&gt;</span>maven-surefire-plugin<span class="nt">&lt;/artifactId&gt;</span> <span class="nt">&lt;version&gt;</span>2.xx.yy<span class="nt">&lt;/version&gt;</span> <span class="nt">&lt;configuration&gt;</span> <span class="nt">&lt;systemPropertyVariables&gt;</span> ... <span class="nt">&lt;chromeoptions.prefs&gt;</span>intl.accept_languages=de<span class="nt">&lt;/chromeoptions.prefs&gt;</span> <span class="nt">&lt;/systemPropertyVariables&gt;</span> <span class="nt">&lt;/configuration&gt;</span> <span class="nt">&lt;/plugin&gt;</span> ... </code></pre></div></div> <h3 id="gradle">Gradle</h3> <p>аналогично для Gradle в <code class="language-plaintext highlighter-rouge">gradle.properties</code> (вам придётся еще добавить строчку-другую в <code class="language-plaintext highlighter-rouge">build.gradle</code> чтобы передать эти параметры в test task грэдла, но про это - в другой раз)</p> <div class="language-properties highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="py">systemProp.chromeoptions.prefs</span><span class="p">=</span><span class="s">intl.accept_languages=de</span> </code></pre></div></div> <h3 id="командная-строка">Командная строка</h3> <p>Вы можете переопределять значения при запуске <code class="language-plaintext highlighter-rouge">mvn test</code> или <code class="language-plaintext highlighter-rouge">gradle test</code> определяя новое значение в <code class="language-plaintext highlighter-rouge">-Dchromeoptions.prefs=intl.accept_languages=ru</code></p> <h2 id="пример">Пример</h2> <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">"http://wikipedia.org"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"[data-jsl10n=slogan]"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">exactText</span><span class="o">(</span><span class="s">"Die freie Enzyklopädie"</span><span class="o">));</span> </code></pre></div></div> <p>Я желаю всем вам <em><strong>Fröhliche Weihnachten</strong></em> и <em><strong>Guten Rutsch</strong></em>!</p> <p><strong>Alexei Vinogradov</strong></p> http://ru.selenide.org/2019/12/22/advent-calendar-defaulta-lingvo/ http://ru.selenide.org/2019/12/22/advent-calendar-defaulta-lingvo 2019-12-22T00:00:00+00:00 Теория большого вейта <h1 id="теория-большого-вейта">Теория большого вейта</h1> <p>Тема ожиданий вызывает много обсуждений и споров.<br /> Современные веб-сайты создают проблемы для <em>написателей</em> автотестов. Возникает много ситуаций, в которых стандартные методы Selenium неэффективны.</p> <p>Если вы читали документацию Selenide, вы уже знаете, что классические явные ожидания типа</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">element</span> <span class="o">=</span> <span class="o">(</span><span class="k">new</span> <span class="nc">WebDriverWait</span><span class="o">(</span><span class="n">driver</span><span class="o">,</span> <span class="o">&lt;</span><span class="n">timeOutForElement</span><span class="o">&gt;))</span> <span class="o">.</span><span class="na">until</span><span class="o">(</span><span class="nc">ExpectedConditions</span><span class="o">.</span><span class="na">presenceOfElementLocated</span><span class="o">(</span><span class="nc">By</span><span class="o">.</span><span class="na">cssSelector</span><span class="o">(&lt;</span><span class="n">cssSelector</span><span class="o">&gt;)));</span> </code></pre></div></div> <p>или</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">element</span> <span class="o">=</span> <span class="o">(</span><span class="k">new</span> <span class="nc">WebDriverWait</span><span class="o">(</span><span class="n">driver</span><span class="o">,</span> <span class="o">&lt;</span><span class="n">timeOutForElement</span><span class="o">&gt;))</span> <span class="o">.</span><span class="na">until</span><span class="o">(</span><span class="nc">ExpectedConditions</span><span class="o">.</span><span class="na">visibilityOfElementLocated</span><span class="o">(</span><span class="nc">By</span><span class="o">.</span><span class="na">cssSelector</span><span class="o">(&lt;</span><span class="n">cssSelector</span><span class="o">&gt;)));</span> </code></pre></div></div> <p>были заменены в Selenide более коротким конструкциями типа</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">element</span> <span class="o">=</span> <span class="err">$</span><span class="o">(&lt;</span><span class="n">cssSelector</span><span class="o">&gt;).</span><span class="na">should</span><span class="o">(</span><span class="n">exist</span><span class="o">);</span> <span class="n">element</span> <span class="o">=</span> <span class="err">$</span><span class="o">(&lt;</span><span class="n">cssSelector</span><span class="o">&gt;).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">visible</span><span class="o">);</span> </code></pre></div></div> <p><strong>Как известно, ассерты в Selenide - это новая версия явных ожиданий, что хорошо описано в <a href="https://selenide.org/documentation.html">документации</a>.</strong></p> <p>Сегодня мы не будем рассматривать ожидания и ассерты с технической точки зрения, а подумаем, для чего можно использовать ассерты в различных ситуациях.</p> <h2 id="современные-проблемы-требуют-современных-решений">Современные проблемы требуют современных решений</h2> <h3 id="1-threadsleep">1. <code class="language-plaintext highlighter-rouge">Thread.sleep()</code></h3> <p>Это самое ужасное, что может случиться с нашими тестами на Selenium.</p> <p>В некоторых ситуациях мы были вынуждены использовать слипы. У нас просто не было другого решения, чтобы обойти проблему и двигаться дальше. Например, слипы используют, чтобы дождаться окончания загрузки страницы. Иногда - чтобы дождаться какого-то элемента, когда другие ожидания не помогли. Увы, таким образом мы можем терять много времени при запуске теста.</p> <p>Если поставить один слип - это ещё ничего. Вы потеряете, скажем, 4 секунды - не смертельно.<br /> Но если вы используете слип в 150 тестах, время их выполнения увеличится заметно.<br /> Нет смысла объяснять, почему это плохо.</p> <p>Хотя команда <code class="language-plaintext highlighter-rouge">sleep()</code> есть и в Selenide, вышеупомянутые “умные ожидания” делают слипы почти ненужными для ожидания появления чего-то либо на странице.<br /> Смотри следующие пункты.</p> <h3 id="2-как-дождаться-окончания-загрузки-страницы">2. Как дождаться окончания загрузки страницы?</h3> <p>Самый простой способ - выбрать какой-то элемент на странице, который редко меняется (скажем, заголовок), и использовать метод Selenide:</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">cssSelector</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">visible</span><span class="o">);</span> </code></pre></div></div> <p>Selenide сначала попытается найти элемент, а потом проверить, что он видимый.<br /> Если это не удалось за 4 секунды, вы можете сделать вывод, что страница не загрузилась.</p> <p>Ещё вы можете выбрать какой-то элемент на <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="n">element</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">Thread.sleep()</code>.</p> <h3 id="3-изменение-состояния-элемента">3. Изменение состояния элемента</h3> <p>Иногда нам нужно проверить, что состояние элемента поменялось в результате действий пользователя.<br /> Например, элемент может содержать текст, сигнализирующий об успешной или неуспешной загрузке файла.<br /> Допустим, загрузка файла занимает какое-то время, потому что файл большой, или сервер должен запустить какую-то сложную обработку этого файла.</p> <p>Обычно мы в тесте загружаем файл и проверяем состояние элемента (скажем, текст “файл загружен”).<br /> Но как узнать, <em>когда</em> именно состояние элемента должно поменяться? Загрузка-то происходит не мгновенно.<br /> В этой ситуации многие используют <code class="language-plaintext highlighter-rouge">Thread.sleep()</code>.</p> <p>А в Selenide у нас есть умный инструмент для “отложенной” проверки состояния элемента:</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">cssSelector</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">exactText</span><span class="o">(&lt;</span><span class="n">expectedText</span><span class="o">&gt;));</span> </code></pre></div></div> <p>В этом случае Selenide сам дождётся, пока состояние элемента изменится, и в нём появится нужный текст.<br /> Нам не нужно писать лишних строк для ожиданий, и мы можем быть уверены, что Selenide точно дождётся.</p> <h3 id="что-теперь">Что теперь?</h3> <p>Мы рассмотрели всего лишь несколько простых идей, как можно “ждать” с помощью Selenide.<br /> В реальности ситуаций намного больше. И здорово, что теперь у нас есть хороший инструмент, позволяющий нам обходится без слипов и не терять драгоценное время.<br /> Используйте умные инструменты и не теряйте время - время ценно. :)</p> <p>Maciej Grymuza (figrym@gmail.com)</p> http://ru.selenide.org/2019/12/20/advent-calendar-big-wait-theory/ http://ru.selenide.org/2019/12/20/advent-calendar-big-wait-theory 2019-12-20T00:00:00+00:00 Как получить сетевые запросы с помощью прокси <p>Привет!</p> <p>В предыдущих постах нашего рождественского календаря мы рассмотрели два способа получить сетевые запросы между браузером и приложением.<br /> Оба нас расстроили тем, что не позволяют прочитать тело запроса/ответа.</p> <p>Наконец, дошла очередь до третьего способа - через встроенный прокси-сервер.</p> <h3 id="перед-тестом">Перед тестом</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">proxyEnabled</span> <span class="o">=</span> <span class="kc">true</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">BrowserMobProxy</span> <span class="n">bmp</span> <span class="o">=</span> <span class="nc">WebDriverRunner</span><span class="o">.</span><span class="na">getSelenideProxy</span><span class="o">().</span><span class="na">getProxy</span><span class="o">();</span> <span class="c1">// запоминать тело запросов (по умолчанию тело не запоминается, ибо может быть большим)</span> <span class="n">bmp</span><span class="o">.</span><span class="na">setHarCaptureTypes</span><span class="o">(</span><span class="nc">CaptureType</span><span class="o">.</span><span class="na">getAllContentCaptureTypes</span><span class="o">());</span> <span class="c1">// запоминать как запросы, так и ответы</span> <span class="n">bmp</span><span class="o">.</span><span class="na">enableHarCaptureTypes</span><span class="o">(</span><span class="nc">CaptureType</span><span class="o">.</span><span class="na">REQUEST_CONTENT</span><span class="o">,</span> <span class="nc">CaptureType</span><span class="o">.</span><span class="na">RESPONSE_CONTENT</span><span class="o">);</span> <span class="c1">// начинай запись!</span> <span class="n">bmp</span><span class="o">.</span><span class="na">newHar</span><span class="o">(</span><span class="s">"pofig"</span><span class="o">);</span> </code></pre></div></div> <h3 id="после-теста">После теста</h3> <p>Теперь нужно получить HAR и анализировать все записи в нём:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">HarEntry</span><span class="o">&gt;</span> <span class="n">requests</span> <span class="o">=</span> <span class="n">bmp</span><span class="o">.</span><span class="na">getHar</span><span class="o">().</span><span class="na">getLog</span><span class="o">().</span><span class="na">getEntries</span><span class="o">();</span> </code></pre></div></div> <p>HAR (HTTP Archive) - это типа такой “архив” со всеми сетевыми запросами и ответами (“entries”).</p> <p>Каждая запись - это и есть запрос от тестируемого приложения к серверу.<br /> Внутри есть все данные: URL, request, response, их http status и body.<br /> Всё, о чём мы так давно мечтали.</p> <p><img src="/images/2019/12/har.entries.png" alt="HAR entries" /></p> <h3 id="плюсы">Плюсы:</h3> <ul> <li>Есть все данные, которые нам нужны</li> <li>Легко анализировать программно</li> <li>Работает во всех браузерах</li> </ul> <h3 id="минусы">Минусы:</h3> <p>Минус только один: иногда у людей возникают сложности с запуском прокси, когда браузер и тесты бегут на разных машинах, и с “браузерной” машины нет доступа к “тестовой” машине. Хотя я никогда не понимал, зачем такие сложности. Запускайте тесты и браузеры на одной и той же машине - ВСЁ будет в стотыщ раз ПРОЩЕ.<br /> Надо параллелить - параллельте тесты. Нужен кластер - запускайте ТЕСТЫ на разных нодах кластера (а с ними запустятся и браузеры). Зачем всё усложнять?</p> <h2 id="что-теперь">Что теперь?</h2> <p>Теперь мы умеем читать сетевые запросы при прогоне тестов.<br /> Но я вообще-то надеюсь, что обычно это вам не должно быть нужно. Ну может, в каких-то очень уж запутанных случаях.<br /> Обычно должно быть достаточно почитать логи приложения, чтобы понять, какие запросы к нему прилетали. Будьте проще.</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2019/12/18/advent-calendar-network-logs-with-proxy/ http://ru.selenide.org/2019/12/18/advent-calendar-network-logs-with-proxy 2019-12-18T00:00:00+00:00 Как получить логи браузера через JavaScript <p>Привет!</p> <p>В прошлом посте нашего рождественского календаря мы пробовали получить логи хрома с помощью <em>капабилити</em> “goog:loggingPrefs”.<br /> А сегодня попробуем другой способ - с помощью JavaScript.</p> <p>Итак, надо всего лишь в конце теста дёрнуть такой вот JavaScript:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">String</span> <span class="n">js</span> <span class="o">=</span> <span class="s">"var performance = window.performance || window.mozPerformance"</span> <span class="o">+</span> <span class="s">" || window.msPerformance || window.webkitPerformance || {};"</span> <span class="o">+</span> <span class="s">" return performance.getEntries() || {};"</span><span class="o">;</span> <span class="nc">String</span> <span class="n">netData</span> <span class="o">=</span> <span class="n">executeJavaScript</span><span class="o">(</span><span class="n">js</span><span class="o">).</span><span class="na">toString</span><span class="o">();</span> <span class="n">logger</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"Network traffic: {}"</span><span class="o">,</span> <span class="n">netData</span><span class="o">);</span> </code></pre></div></div> <p>Результат получается примерно такой:</p> <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">Network</span><span class="w"> </span><span class="err">traffic:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="p">{</span><span class="err">name=https://selenide.org/quick-start.html</span><span class="p">,</span><span class="w"> </span><span class="err">connectEnd=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">connectStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">decodedBodySize=</span><span class="mi">32582</span><span class="p">,</span><span class="w"> </span><span class="err">domComplete=</span><span class="mi">724</span><span class="p">,</span><span class="w"> </span><span class="err">domContentLoadedEventEnd=</span><span class="mi">119</span><span class="p">,</span><span class="w"> </span><span class="err">domContentLoadedEventStart=</span><span class="mi">115</span><span class="p">,</span><span class="w"> </span><span class="err">domInteractive=</span><span class="mi">104</span><span class="p">,</span><span class="w"> </span><span class="err">domainLookupEnd=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">domainLookupStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">duration=</span><span class="mi">724</span><span class="p">,</span><span class="w"> </span><span class="err">encodedBodySize=</span><span class="mi">32582</span><span class="p">,</span><span class="w"> </span><span class="err">entryType=navigation</span><span class="p">,</span><span class="w"> </span><span class="err">fetchStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">initiatorType=navigation</span><span class="p">,</span><span class="w"> </span><span class="err">loadEventEnd=</span><span class="mi">724</span><span class="p">,</span><span class="w"> </span><span class="err">loadEventStart=</span><span class="mi">724</span><span class="p">,</span><span class="w"> </span><span class="err">nextHopProtocol=http/</span><span class="mf">1.1</span><span class="p">,</span><span class="w"> </span><span class="err">redirectCount=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">redirectEnd=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">redirectStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">requestStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">responseEnd=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">responseStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">secureConnectionStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">serverTiming=</span><span class="p">[],</span><span class="w"> </span><span class="err">startTime=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">transferSize=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">type=navigate</span><span class="p">,</span><span class="w"> </span><span class="err">unloadEventEnd=</span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="err">unloadEventStart=</span><span class="mi">9</span><span class="p">,</span><span class="w"> </span><span class="err">workerStart=</span><span class="mi">0</span><span class="p">},</span><span class="w"> </span><span class="p">{</span><span class="err">name=https://selenide.org/assets/themes/ingmar/css/styles.css?</span><span class="mi">001</span><span class="p">,</span><span class="w"> </span><span class="err">connectEnd=</span><span class="mi">12</span><span class="p">,</span><span class="w"> </span><span class="err">connectStart=</span><span class="mi">12</span><span class="p">,</span><span class="w"> </span><span class="err">decodedBodySize=</span><span class="mi">8177</span><span class="p">,</span><span class="w"> </span><span class="err">domainLookupEnd=</span><span class="mi">12</span><span class="p">,</span><span class="w"> </span><span class="err">domainLookupStart=</span><span class="mi">12</span><span class="p">,</span><span class="w"> </span><span class="err">duration=</span><span class="mi">29</span><span class="p">,</span><span class="w"> </span><span class="err">encodedBodySize=</span><span class="mi">8177</span><span class="p">,</span><span class="w"> </span><span class="err">entryType=resource</span><span class="p">,</span><span class="w"> </span><span class="err">fetchStart=</span><span class="mi">12</span><span class="p">,</span><span class="w"> </span><span class="err">initiatorType=link</span><span class="p">,</span><span class="w"> </span><span class="err">nextHopProtocol=http/</span><span class="mf">1.1</span><span class="p">,</span><span class="w"> </span><span class="err">redirectEnd=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">redirectStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">requestStart=</span><span class="mi">12</span><span class="p">,</span><span class="w"> </span><span class="err">responseEnd=</span><span class="mi">41</span><span class="p">,</span><span class="w"> </span><span class="err">responseStart=</span><span class="mi">21</span><span class="p">,</span><span class="w"> </span><span class="err">secureConnectionStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">serverTiming=</span><span class="p">[],</span><span class="w"> </span><span class="err">startTime=</span><span class="mi">12</span><span class="p">,</span><span class="w"> </span><span class="err">transferSize=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">workerStart=</span><span class="mi">0</span><span class="p">},</span><span class="w"> </span><span class="p">{</span><span class="err">name=https://ajax.googleapis.com/ajax/libs/jquery/</span><span class="mf">2.1</span><span class="err">.</span><span class="mi">1</span><span class="err">/jquery.min.js</span><span class="p">,</span><span class="w"> </span><span class="err">connectEnd=</span><span class="mi">13</span><span class="p">,</span><span class="w"> </span><span class="err">connectStart=</span><span class="mi">13</span><span class="p">,</span><span class="w"> </span><span class="err">decodedBodySize=</span><span class="mi">84245</span><span class="p">,</span><span class="w"> </span><span class="err">domainLookupEnd=</span><span class="mi">13</span><span class="p">,</span><span class="w"> </span><span class="err">domainLookupStart=</span><span class="mi">13</span><span class="p">,</span><span class="w"> </span><span class="err">duration=</span><span class="mi">28</span><span class="p">,</span><span class="w"> </span><span class="err">encodedBodySize=</span><span class="mi">84245</span><span class="p">,</span><span class="w"> </span><span class="err">entryType=resource</span><span class="p">,</span><span class="w"> </span><span class="err">fetchStart=</span><span class="mi">13</span><span class="p">,</span><span class="w"> </span><span class="err">initiatorType=script</span><span class="p">,</span><span class="w"> </span><span class="err">nextHopProtocol=http/</span><span class="mf">1.1</span><span class="p">,</span><span class="w"> </span><span class="err">redirectEnd=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">redirectStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">requestStart=</span><span class="mi">13</span><span class="p">,</span><span class="w"> </span><span class="err">responseEnd=</span><span class="mi">41</span><span class="p">,</span><span class="w"> </span><span class="err">responseStart=</span><span class="mi">21</span><span class="p">,</span><span class="w"> </span><span class="err">secureConnectionStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">serverTiming=</span><span class="p">[],</span><span class="w"> </span><span class="err">startTime=</span><span class="mi">13</span><span class="p">,</span><span class="w"> </span><span class="err">transferSize=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">workerStart=</span><span class="mi">0</span><span class="p">}</span><span class="w"> </span><span class="p">]</span><span class="w"> </span></code></pre></div></div> <h3 id="плюсы">Плюсы:</h3> <ul> <li>Не нужно никак настраивать браузер. Оно работает из коробки.</li> <li>Работает во всех браузерах (кажется?)</li> </ul> <h3 id="минусы">Минусы:</h3> <ul> <li>Здесь всё ещё нет тела запроса.</li> <li>Это невалидный JSON. Распарсить его стандартным парсером не получится. Придётся придумывать какой-то свой обработчик.</li> </ul> <p>Но этот способ вполне подходит, чтобы просто посмотреть глазами и прикинуть, что происходит.</p> <h2 id="что-теперь">Что теперь?</h2> <p>Наша последняя надежда - получить запросы и ответы с помощью встроенного прокси-сервера. Этот способ мы рассмотрим в следующем посте.</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2019/12/17/advent-calendar-browser-logs-with-js/ http://ru.selenide.org/2019/12/17/advent-calendar-browser-logs-with-js 2019-12-17T00:00:00+00:00 Как получить логи браузера <p>Привет!</p> <p>Мы продолжаем наш рождественский календарь.<br /> На сей раз мы посмотрим, как можно взглянуть хрому под вкладку “developer tools”.<br /> Это на случай, если вы хотите понять, какие ошибки писались и какие сетевые запросы летели из тестируемого приложения во время прогона тестов.</p> <p>Chromedriver предлагает следующий рецепт.</p> <h3 id="1-добавить-щепотку-строк-при-открытии-браузера">1. Добавить щепотку строк при открытии браузера:</h3> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">LoggingPreferences</span> <span class="n">logPrefs</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">LoggingPreferences</span><span class="o">();</span> <span class="n">logPrefs</span><span class="o">.</span><span class="na">enable</span><span class="o">(</span><span class="nc">LogType</span><span class="o">.</span><span class="na">BROWSER</span><span class="o">,</span> <span class="nc">Level</span><span class="o">.</span><span class="na">ALL</span><span class="o">);</span> <span class="n">logPrefs</span><span class="o">.</span><span class="na">enable</span><span class="o">(</span><span class="nc">LogType</span><span class="o">.</span><span class="na">PERFORMANCE</span><span class="o">,</span> <span class="nc">Level</span><span class="o">.</span><span class="na">ALL</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">"goog:loggingPrefs"</span><span class="o">,</span> <span class="n">logPrefs</span><span class="o">);</span> </code></pre></div></div> <p>До какой-то версии эта <em>капабилитя</em> называлась “loggingPrefs”, потом переименовали в “goog:loggingPrefs”.<br /> Не знаю, как в других браузерах.</p> <p>Кстати, помимо <code class="language-plaintext highlighter-rouge">BROWSER</code> и <code class="language-plaintext highlighter-rouge">PERFORMANCE</code>, есть и другие типы логов, но у меня они как-то нестабильно работали, да я и пользы в них не увидел. Знаете больше? Делитесь!</p> <h3 id="2-в-конце-теста-снять-пенку-с-логов">2. В конце теста снять пенку с логов:</h3> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Logs</span> <span class="n">logs</span> <span class="o">=</span> <span class="n">getWebDriver</span><span class="o">().</span><span class="na">manage</span><span class="o">().</span><span class="na">logs</span><span class="o">();</span> <span class="n">printLog</span><span class="o">(</span><span class="n">logs</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="nc">LogType</span><span class="o">.</span><span class="na">BROWSER</span><span class="o">));</span> <span class="kt">void</span> <span class="nf">printLog</span><span class="o">(</span><span class="nc">LogEntries</span> <span class="n">entries</span><span class="o">)</span> <span class="o">{</span> <span class="n">logger</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"{} log entries found"</span><span class="o">,</span> <span class="n">entries</span><span class="o">.</span><span class="na">getAll</span><span class="o">().</span><span class="na">size</span><span class="o">());</span> <span class="k">for</span> <span class="o">(</span><span class="nc">LogEntry</span> <span class="n">entry</span> <span class="o">:</span> <span class="n">entries</span><span class="o">)</span> <span class="o">{</span> <span class="n">logger</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"{} {} {}"</span><span class="o">,</span> <span class="k">new</span> <span class="nf">Date</span><span class="o">(</span><span class="n">entry</span><span class="o">.</span><span class="na">getTimestamp</span><span class="o">()),</span> <span class="n">entry</span><span class="o">.</span><span class="na">getLevel</span><span class="o">(),</span> <span class="n">entry</span><span class="o">.</span><span class="na">getMessage</span><span class="o">()</span> <span class="o">);</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div></div> <h3 id="3-блюдо-подаётся-к-отчёту-примерно-в-таком-виде">3. Блюдо подаётся к отчёту примерно в таком виде:</h3> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">BROWSER</span> <span class="nl">logs:</span> <span class="nc">Mon</span> <span class="nc">Dec</span> <span class="mi">16</span> <span class="mi">19</span><span class="o">:</span><span class="mi">29</span><span class="o">:</span><span class="mi">42</span> <span class="no">EET</span> <span class="mi">2019</span> <span class="no">SEVERE</span> <span class="nl">http:</span><span class="c1">//localhost:9126/page/image/payment-promo-campaign-ozon.png - Failed to load resource: the server responded with a status of 404 (Not Found)</span> <span class="nc">Mon</span> <span class="nc">Dec</span> <span class="mi">16</span> <span class="mi">19</span><span class="o">:</span><span class="mi">49</span><span class="o">:</span><span class="mi">14</span> <span class="no">EET</span> <span class="mi">2019</span> <span class="no">INFO</span> <span class="n">console</span><span class="o">-</span><span class="n">api</span> <span class="mi">19</span><span class="o">:</span><span class="mi">16</span> <span class="s">"start loading loans"</span> <span class="nc">Mon</span> <span class="nc">Dec</span> <span class="mi">16</span> <span class="mi">19</span><span class="o">:</span><span class="mi">49</span><span class="o">:</span><span class="mi">14</span> <span class="no">EET</span> <span class="mi">2019</span> <span class="no">INFO</span> <span class="n">console</span><span class="o">-</span><span class="n">api</span> <span class="mi">21</span><span class="o">:</span><span class="mi">18</span> <span class="s">"loaded loans"</span> </code></pre></div></div> <p>Здесь видны все логи, что есть обычно в Developer Tools -&gt; Console. В том числе сообщения <code class="language-plaintext highlighter-rouge">console.log</code> и ошибки JavaScript.</p> <h3 id="4-для-гурманов-можно-подать-десерт">4. Для гурманов можно подать десерт</h3> <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">PERFORMANCE</span><span class="w"> </span><span class="err">logs:</span><span class="w"> </span><span class="p">{</span><span class="nl">"message"</span><span class="p">:{</span><span class="nl">"method"</span><span class="p">:</span><span class="s2">"Network.loadingFinished"</span><span class="p">,</span><span class="nl">"params"</span><span class="p">:{</span><span class="nl">"encodedDataLength"</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="nl">"requestId"</span><span class="p">:</span><span class="s2">"2C9E49BC49DCD3CA6EA9644255E34DE5"</span><span class="p">,</span><span class="nl">"shouldReportCorbBlocking"</span><span class="p">:</span><span class="kc">false</span><span class="p">,</span><span class="nl">"timestamp"</span><span class="p">:</span><span class="mf">141439.076528</span><span class="p">}},</span><span class="nl">"webview"</span><span class="p">:</span><span class="s2">"FF1A4E4EAAD7143749CD3740DF9BB95F"</span><span class="p">}</span><span class="w"> </span><span class="p">{</span><span class="nl">"message"</span><span class="p">:{</span><span class="nl">"method"</span><span class="p">:</span><span class="s2">"Page.loadEventFired"</span><span class="p">,</span><span class="nl">"params"</span><span class="p">:{</span><span class="nl">"timestamp"</span><span class="p">:</span><span class="mf">141439.234207</span><span class="p">}},</span><span class="nl">"webview"</span><span class="p">:</span><span class="s2">"FF1A4E4EAAD7143749CD3740DF9BB95F"</span><span class="p">}</span><span class="w"> </span><span class="p">{</span><span class="nl">"message"</span><span class="p">:{</span><span class="nl">"method"</span><span class="p">:</span><span class="s2">"Page.frameStoppedLoading"</span><span class="p">,</span><span class="nl">"params"</span><span class="p">:{</span><span class="nl">"frameId"</span><span class="p">:</span><span class="s2">"FF1A4E4EAAD7143749CD3740DF9BB95F"</span><span class="p">}},</span><span class="nl">"webview"</span><span class="p">:</span><span class="s2">"FF1A4E4EAAD7143749CD3740DF9BB95F"</span><span class="p">}</span><span class="w"> </span><span class="p">{</span><span class="nl">"message"</span><span class="p">:{</span><span class="nl">"method"</span><span class="p">:</span><span class="s2">"Page.domContentEventFired"</span><span class="p">,</span><span class="nl">"params"</span><span class="p">:{</span><span class="nl">"timestamp"</span><span class="p">:</span><span class="mf">141439.234834</span><span class="p">}},</span><span class="nl">"webview"</span><span class="p">:</span><span class="s2">"FF1A4E4EAAD7143749CD3740DF9BB95F"</span><span class="p">}</span><span class="w"> </span><span class="p">{</span><span class="nl">"message"</span><span class="p">:{</span><span class="nl">"method"</span><span class="p">:</span><span class="s2">"Page.frameResized"</span><span class="p">,</span><span class="nl">"params"</span><span class="p">:{}},</span><span class="nl">"webview"</span><span class="p">:</span><span class="s2">"FF1A4E4EAAD7143749CD3740DF9BB95F"</span><span class="p">}</span><span class="w"> </span><span class="err">...</span><span class="w"> </span><span class="p">{</span><span class="nl">"message"</span><span class="p">:{</span><span class="nl">"method"</span><span class="p">:</span><span class="s2">"Network.dataReceived"</span><span class="p">,</span><span class="nl">"params"</span><span class="p">:{</span><span class="nl">"dataLength"</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="nl">"encodedDataLength"</span><span class="p">:</span><span class="mi">327</span><span class="p">,</span><span class="nl">"requestId"</span><span class="p">:</span><span class="s2">"58583.71"</span><span class="p">,</span><span class="nl">"timestamp"</span><span class="p">:</span><span class="mf">141474.021635</span><span class="p">}},</span><span class="nl">"webview"</span><span class="p">:</span><span class="s2">"FF1A4E4EAAD7143749CD3740DF9BB95F"</span><span class="p">}</span><span class="w"> </span><span class="p">{</span><span class="nl">"message"</span><span class="p">:{</span><span class="nl">"method"</span><span class="p">:</span><span class="s2">"Network.loadingFinished"</span><span class="p">,</span><span class="nl">"params"</span><span class="p">:{</span><span class="nl">"encodedDataLength"</span><span class="p">:</span><span class="mi">586</span><span class="p">,</span><span class="nl">"requestId"</span><span class="p">:</span><span class="s2">"58583.71"</span><span class="p">,</span><span class="nl">"shouldReportCorbBlocking"</span><span class="p">:</span><span class="kc">false</span><span class="p">,</span><span class="nl">"timestamp"</span><span class="p">:</span><span class="mf">141473.994219</span><span class="p">}},</span><span class="nl">"webview"</span><span class="p">:</span><span class="s2">"FF1A4E4EAAD7143749CD3740DF9BB95F"</span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <h3 id="плюс">Плюс</h3> <p>Каждая запись - это валидный JSON, его вполне можно парсить и анализировать прямо в тестах.</p> <p>Вот так выглядит отформатированная первая запись:</p> <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w"> </span><span class="nl">"message"</span><span class="p">:{</span><span class="w"> </span><span class="nl">"method"</span><span class="p">:</span><span class="s2">"Network.loadingFinished"</span><span class="p">,</span><span class="w"> </span><span class="nl">"params"</span><span class="p">:{</span><span class="w"> </span><span class="nl">"encodedDataLength"</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="nl">"requestId"</span><span class="p">:</span><span class="s2">"2C9E49BC49DCD3CA6EA9644255E34DE5"</span><span class="p">,</span><span class="w"> </span><span class="nl">"shouldReportCorbBlocking"</span><span class="p">:</span><span class="kc">false</span><span class="p">,</span><span class="w"> </span><span class="nl">"timestamp"</span><span class="p">:</span><span class="mf">141439.076528</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="nl">"webview"</span><span class="p">:</span><span class="s2">"FF1A4E4EAAD7143749CD3740DF9BB95F"</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <h3 id="минус">Минус:</h3> <ul> <li>Что-то понять из этих логов сложно. Нужно строить поверх какие-то анализаторы.</li> <li>Здесь нет тела запроса.</li> </ul> <h2 id="что-теперь">Что теперь?</h2> <p>В следующий раз вы изучим другие возможности получить логи - со статусами и телами запросов.</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2019/12/16/advent-calendar-browser-logs/ http://ru.selenide.org/2019/12/16/advent-calendar-browser-logs 2019-12-16T00:00:00+00:00 Drag and Drop <p>Привет!</p> <p>В сегодняшнем выпуске рождественского календаря мы посмотрим короткое, но весёлое видео о том, как перетаскивать элементы в Selenide.</p> <h3 id="селенид-умеет-перетаскивать-элементы">Селенид умеет перетаскивать элементы?</h3> <p>Да, в селениде есть метод Drag’n’Drop. Вот скучное описание из блога селенида:</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">"#from"</span><span class="o">).</span><span class="na">dragAndDropTo</span><span class="o">(</span><span class="s">"#to"</span><span class="o">)</span> </code></pre></div></div> <p>А вот весёленькое описание от Martin Škarbala:</p> <iframe width="800" height="490" src="https://www.youtube.com/embed/OSnwiosrMq0" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe> <p>Вот это подача!</p> <p><a href="http://asolntsev.github.io/">Андрей Солнцев</a></p> <p>ru.selenide.org</p> http://ru.selenide.org/2019/12/15/advent-calendar-drag-and-drop/ http://ru.selenide.org/2019/12/15/advent-calendar-drag-and-drop 2019-12-15T00:00:00+00:00 Actions <p>Привет!</p> <p>В сегодняшнем выпуске рождественского календаря мы рассмотрим, как можно использовать “действия” (Actions) в Selenide.</p> <p>Иногда при написании автотестов мы сталкиваемся со странными проблемами. Уверен на 100%, каждый из нас испытывал или будет испытывать необычные проблемы, которые блокируют нашу работу. Например, у нас часто не получается кликнуть на какой-то элемент, и стандартная селениумовская/селенидовская команда типа</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">element</span><span class="o">.</span><span class="na">click</span><span class="o">();</span> </code></pre></div></div> <p>не работает. Причин, по которым клик может не срабатывать - множество. Но мы не можем сдаться просто так, мы должны найти какое-то решение. В Selenium для таких случаев есть класс <code class="language-plaintext highlighter-rouge">Actions</code>, который позволяет выполнить клик иначе:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">WebElement</span> <span class="n">element</span> <span class="o">=</span> <span class="o">&lt;</span><span class="nc">Some</span> <span class="n">selector</span><span class="o">&gt;;</span> <span class="nc">Actions</span> <span class="n">actions</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Actions</span><span class="o">(</span><span class="n">driver</span><span class="o">);</span> <span class="n">actions</span><span class="o">.</span><span class="na">moveToElement</span><span class="o">(</span><span class="n">element</span><span class="o">);</span> <span class="n">actions</span><span class="o">.</span><span class="na">click</span><span class="o">();</span> <span class="n">actions</span><span class="o">.</span><span class="na">build</span><span class="o">().</span><span class="na">perform</span><span class="o">();</span> </code></pre></div></div> <p>Этот вариант иногда срабатывает там, где обычный клик бессилен.</p> <h4 id="но-как-сделать-это-в-selenide">Но как сделать это в Selenide?</h4> <p>Оказывается, в Selenide это ещё проще, чем в Selenium (как, собственно, и всё в Selenide :)). <br /> В Selenide тоже есть <code class="language-plaintext highlighter-rouge">Actions</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">SelenideElement</span> <span class="n">element</span> <span class="o">=</span> <span class="err">$</span><span class="o">(&lt;</span><span class="n">some</span> <span class="n">selector</span><span class="o">&gt;);</span> <span class="n">actions</span><span class="o">().</span><span class="na">moveToElement</span><span class="o">(</span><span class="n">element</span><span class="o">).</span><span class="na">click</span><span class="o">(</span><span class="n">element</span><span class="o">).</span><span class="na">perform</span><span class="o">();</span> </code></pre></div></div> <p>Здесь <code class="language-plaintext highlighter-rouge">actions()</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">Selenide</span><span class="o">.*;</span> </code></pre></div></div> <p>Заметить, чтобы использовать <code class="language-plaintext highlighter-rouge">actions()</code>, не нужен webdriver!</p> <h5 id="чумачечий-drag-and-drop">Чумачечий drag and drop</h5> <p>Если вы читали документацию, вы знаете, что в Selenide по умолчанию есть два типа операций “drag and drop”:</p> <ol> <li><code class="language-plaintext highlighter-rouge">dragAndDropTo​(java.lang.String targetCssSelector);</code></li> <li><code class="language-plaintext highlighter-rouge">dragAndDropTo​(org.openqa.selenium.WebElement target);</code></li> </ol> <p>Первый метод перетаскивает элемент в цель по CSS локатору. Второй - в другой WebElement.</p> <p>Но что, если мы не знаем точно, в какой элемент нужно перетащить?<br /> Допустим, у нас есть просто пустая страница, и мы хотим перетащить несколько объектов в разные места на этой странице.<br /> И тут снова на помощь приходят <code class="language-plaintext highlighter-rouge">Actions</code>. В Selenium мы бы сделали это примерно так:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">WebElement</span> <span class="n">element</span> <span class="o">=</span> <span class="n">driver</span><span class="o">.</span><span class="na">findElement</span><span class="o">(</span><span class="nc">By</span><span class="o">.</span><span class="na">some</span><span class="o">);</span> <span class="nc">Actions</span> <span class="n">actions</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Actions</span><span class="o">(</span><span class="n">driver</span><span class="o">);</span> <span class="n">actions</span><span class="o">.</span><span class="na">dragAndDropBy</span><span class="o">(</span><span class="n">element</span><span class="o">,</span> <span class="n">xOffset</span><span class="o">,</span> <span class="n">yOffset</span><span class="o">).</span><span class="na">perform</span><span class="o">();</span> </code></pre></div></div> <p>Где <code class="language-plaintext highlighter-rouge">xOffset</code> и <code class="language-plaintext highlighter-rouge">yOffset</code> - сдвиг по горизонтали и вертикали.</p> <p>В Selenide это выглядит чуть короче:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">SelenideElement</span> <span class="n">element</span> <span class="o">=</span> <span class="o">&lt;</span><span class="nc">Some</span> <span class="n">selector</span><span class="o">&gt;;</span> <span class="n">actions</span><span class="o">().</span><span class="na">dragAndDropBy</span><span class="o">(</span><span class="n">element</span><span class="o">,</span> <span class="n">xOffset</span><span class="o">,</span> <span class="n">yOffset</span><span class="o">).</span><span class="na">perform</span><span class="o">();</span> </code></pre></div></div> <p>Таким образом мы можем перетащить элемент в любую точку, даже не зная локатора цели.</p> <h2 id="что-дальше">Что дальше?</h2> <p>Конечно же, это только пара примеров использования <code class="language-plaintext highlighter-rouge">actions()</code> в Selenide, и вы можете экспериментировать и находить другие варианты.</p> <p>Наслаждайтесь <code class="language-plaintext highlighter-rouge">actions()</code>!</p> <p>Maciej Grymuza (figrym@gmail.com)</p> http://ru.selenide.org/2019/12/12/advent-calendar-actions/ http://ru.selenide.org/2019/12/12/advent-calendar-actions 2019-12-12T00:00:00+00:00 Как скачать файл с помощью Selenide <p>Добрый вечер!</p> <p>На дворе декабрь, и в сегодняшнем посте рождественского календаря Selenide мы поговорим о том, какие возможности для скачивания файлов есть в Selenide.</p> <p><strong>UPD</strong><br /> Ниже описаны только два способа скачивания - <a href="#HTTPGET"><code class="language-plaintext highlighter-rouge">HTTPGET</code></a> и <a href="#PROXY"><code class="language-plaintext highlighter-rouge">PROXY</code></a>. Позже <a href="/2020/07/08/selenide-5.13.0/#new-file-download-mode-folder">появился третий способ <code class="language-plaintext highlighter-rouge">FOLDER</code></a>. Возможно, вам нужен как раз он, если у вашей ссылки нет атрибута <code class="language-plaintext highlighter-rouge">href</code>, и прокси у вас не заводится.</p> <p><br /></p> <h1 id="как-я-могу-скачать-файл-в-моём-тесте">Как я могу скачать файл в моём тесте?</h1> <p>В какой-то момент нашей карьеры каждый из нас сталкивается с необходимостью скачать какой-то файл в тесте.</p> <p>Как мы помним, в Selenium это было непросто, потому что для разных браузеров требуются разные настройки.<br /> Например, вот так выглядит создание профиля Firefox с нужными настройками:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">profile</span><span class="o">.</span><span class="na">setPreference</span><span class="o">(</span><span class="s">"browser.download.dir"</span><span class="o">,</span> <span class="n">downloadPath</span><span class="o">);</span> <span class="n">profile</span><span class="o">.</span><span class="na">setPreference</span><span class="o">(</span><span class="s">"browser.download.folderList"</span><span class="o">,</span> <span class="mi">2</span><span class="o">);</span> <span class="n">profile</span><span class="o">.</span><span class="na">setPreference</span><span class="o">(</span><span class="s">"browser.download.manager.showWhenStarting"</span><span class="o">,</span> <span class="kc">false</span><span class="o">);</span> <span class="n">profile</span><span class="o">.</span><span class="na">setPreference</span><span class="o">(</span><span class="s">"browser.helperApps.alwaysAsk.force"</span><span class="o">,</span> <span class="kc">false</span><span class="o">);</span> <span class="n">profile</span><span class="o">.</span><span class="na">setPreference</span><span class="o">(</span><span class="s">"browser.helperApps.neverAsk.saveToDisk"</span><span class="o">,</span> <span class="n">mimeTypes</span><span class="o">);</span> <span class="n">profile</span><span class="o">.</span><span class="na">setPreference</span><span class="o">(</span><span class="s">"browser.download.manager.focusWhenStarting"</span><span class="o">,</span><span class="kc">false</span><span class="o">);</span> <span class="n">profile</span><span class="o">.</span><span class="na">setPreference</span><span class="o">(</span><span class="s">"browser.download.manager.useWindow"</span><span class="o">,</span> <span class="kc">false</span><span class="o">);</span> <span class="n">profile</span><span class="o">.</span><span class="na">setPreference</span><span class="o">(</span><span class="s">"browser.download.manager.showAlertOnComplete"</span><span class="o">,</span> <span class="kc">false</span><span class="o">);</span> <span class="n">profile</span><span class="o">.</span><span class="na">setPreference</span><span class="o">(</span><span class="s">"pdfjs.disabled"</span><span class="o">,</span> <span class="kc">true</span><span class="o">);</span> </code></pre></div></div> <h3 id="HTTPGET">А в Selenide</h3> <p>Проблема решается гораздо проще - методом <code class="language-plaintext highlighter-rouge">$.download()</code>.</p> <p>Чтобы скачать файл, в Selenide достаточно просто вызвать метод:</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="n">element</span><span class="o">.</span><span class="na">download</span><span class="o">();</span> </code></pre></div></div> <p>И Selenide автоматически сделает всё, что надо. Вам не придётся возиться со всплывающим окошком, которое спрашивает, куда сохранить файл, и потом закрывать его.</p> <p>Selenide сохранит скачанный файл в папку <code class="language-plaintext highlighter-rouge">build/reports/tests</code>. Это та же папка, где Gradle генерирует результаты прогона тестов, так что их как раз удобно видеть вместе.</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">downloadsFolder</span> <span class="o">=</span> <span class="o">&lt;</span><span class="n">desired</span> <span class="n">location</span> <span class="k">for</span> <span class="n">downloaded</span> <span class="n">files</span><span class="o">&gt;;</span> </code></pre></div></div> <h3 id="PROXY">НО:</h3> <p>Таким образом можно скачивать файлы только со ссылкой с атрибутом “href”.</p> <p>Но что, если у меня ссылки с атрибутом “href”? Так бывает, например, когда файл скачивается в результате сабмита формы. В этом случае можно скачивать файлы с помощью встроенного в селенид прокси-сервера.</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">proxyEnabled</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">fileDownload</span> <span class="o">=</span> <span class="no">PROXY</span><span class="o">;</span> </code></pre></div></div> <p>После этого мы снова можем вызывать метод <code class="language-plaintext highlighter-rouge">$.download()</code>, но теперь он стал более могущественным и не требует наличия атрибута “href”:</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="n">element</span><span class="o">.</span><span class="na">download</span><span class="o">();</span> </code></pre></div></div> <h3 id="хозяйке-на-заметку">Хозяйке на заметку:</h3> <p>Не забудьте увеличить таймаут, если собираетесь скачивать файл большого размера.</p> <p>Файл будет скачан в папку по умолчанию (что-то типа <code class="language-plaintext highlighter-rouge">C:\downloads and settings\downloads</code>). <br /> Таким образом, скачанный файл окажется в двух местах: <code class="language-plaintext highlighter-rouge">c:\downloads...</code> и <code class="language-plaintext highlighter-rouge">build/reports/tests</code>.</p> <p>Если это для вас проблема, можете в конце теста удалить ненужную папку, чтобы очистить место на диске:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">FileUtils</span><span class="o">.</span><span class="na">deleteDirectory</span><span class="o">(</span><span class="k">new</span> <span class="nc">File</span><span class="o">(&lt;</span><span class="n">папка</span><span class="o">,</span> <span class="n">подлежащая</span>