Selenide2024-09-25T05:52:50+00:00https://selenide.orgAndrei Solntsevandrei.solntsev@gmail.comReleased Selenide 7.5.02024-09-15T00:00:00+00:00https://selenide.org/2024/09/15/selenide-7.5.0
<p>Long time no see, cats!</p>
<p>I wrote the last release notes in April. Since then, we have made a few releases, the most significant was <a href="https://github.com/selenide/selenide/milestone/208?closed=1">7.4.0</a>.</p>
<p>But now it’s time to upgrade to <a href="https://github.com/selenide/selenide/milestone/212?closed=1">Selenide 7.5.0</a>:</p>
<ul>
<li><a href="#new-configuration-for-every-browser">New configuration for every browser</a></li>
<li><a href="#raise-bubbleable-events-from-selects">Fixed events in selects</a></li>
<li><a href="#builder-methods-for-download-options">Shorter API for downloading files</a></li>
<li><a href="#do-not-close-windows-when-downloading-file">Don’t close windows when downloading files</a></li>
<li><a href="#do-not-catch-all-errors">Don’t catch all Errors anymore</a></li>
<li><a href="#generate-error-details-during-error-construction">Fixed custom error formatters</a></li>
<li><a href="#update-dependencies">Updated dependencies</a></li>
<li><a href="#news">News</a></li>
<li><a href="#statistics">Statistics</a></li>
</ul>
<p><br /></p>
<h3 id="new-configuration-for-every-browser">New configuration for every browser</h3>
<p>Selenide has one nuance that might not be obvious to newcomers: all settings in <code class="language-plaintext highlighter-rouge">Configuration</code> class are <em>static</em>.
When you change any setting in one test, it affects other tests as well. It may be especially important when running tests in parallel.</p>
<p>This is, so to speak, not a bug, but a feature: <code class="language-plaintext highlighter-rouge">Configuration</code> contains settings that, it seems, do not need to be changed from test to test.
And those values that can actually be different, we have long ago taken out into the parameters of different methods:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">$.click(usingJavaScript()); // instead of Configuration.clickViaJs = true</code></li>
<li><code class="language-plaintext highlighter-rouge">$.download(using(PROXY)); // instead of Configuration.fileDownload = PROXY</code></li>
</ul>
<p>I wrote more about this evolution <a href="https://www.youtube.com/watch?v=-KGtZoFVzr8&list=PL9Z-JgiTsOYRfoG_mcRBlTUIFPIknhQ6S&ab_channel=ConfEngine">here</a>.</p>
<p>But there was one more setting left: <code class="language-plaintext highlighter-rouge">Configuration.browserCapabilities</code>.
Sometimes you need to set different capabilities in different tests - for example, to set the name of a video in Selenoid.</p>
<p>Strictly speaking, this was possible before as well - just by running the webdriver from your code with any necessary settings.<br />
But now they can be set directly in the <code class="language-plaintext highlighter-rouge">open</code> method:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Test</span> <span class="kt">void</span> <span class="nf">testWithoutProxy</span><span class="o">()</span> <span class="o">{</span>
<span class="n">open</span><span class="o">(</span><span class="s">"/one"</span><span class="o">,</span> <span class="k">new</span> <span class="nc">SelenideConfig</span><span class="o">().</span><span class="na">proxyEnabled</span><span class="o">(</span><span class="kc">false</span><span class="o">).</span><span class="na">fileDownload</span><span class="o">(</span><span class="no">FOLDER</span><span class="o">));</span>
<span class="nc">File</span> <span class="n">report</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#report"</span><span class="o">).</span><span class="na">download</span><span class="o">();</span>
<span class="o">}</span>
<span class="nd">@Test</span> <span class="kt">void</span> <span class="nf">testWithProxy</span><span class="o">()</span> <span class="o">{</span>
<span class="n">open</span><span class="o">(</span><span class="s">"/two"</span><span class="o">,</span> <span class="k">new</span> <span class="nc">SelenideConfig</span><span class="o">().</span><span class="na">proxyEnabled</span><span class="o">(</span><span class="kc">true</span><span class="o">).</span><span class="na">fileDownload</span><span class="o">(</span><span class="no">PROXY</span><span class="o">));</span>
<span class="nc">File</span> <span class="n">cv</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#cv"</span><span class="o">).</span><span class="na">download</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Be careful not to overuse it.</p>
<p>NB! When you call method <code class="language-plaintext highlighter-rouge">open(url, config)</code>, and some browser was already opened by that moment (apparently by a previous test), then Selenide will close this browser.
This may slow down your tests due to constant reopening of browsers. Keep this in mind.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1372">issue 1372</a> and <a href="https://github.com/selenide/selenide/pull/2846">PR 2846</a>.</p>
<p><br /></p>
<h3 id="raise-bubbleable-events-from-selects">Fixed events in selects</h3>
<p>In <a href="https://github.com/selenide/selenide/releases/tag/v7.4.2">Selenide 7.4.2</a> we improved working with <code class="language-plaintext highlighter-rouge"><select></code>s in Vue.js:
started throwing <code class="language-plaintext highlighter-rouge">input</code> events in addition to <code class="language-plaintext highlighter-rouge">change</code>.
But we accidentally changed the events themselves: they were no longer “bubbleable”.
That broke the processing of selects in some other frameworks (when the <code class="language-plaintext highlighter-rouge">change</code> event handler is bound not to select itself, but to its parent).</p>
<p>Now we fixed it. You can again choose options in your favorite selects in preferred way:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">$("#migrants").selectOption("Abduct neighbours' pets");</code></li>
<li><code class="language-plaintext highlighter-rouge">$("#migrants").selectOptionContainingText("abbed ducks by their nec");</code></li>
<li><code class="language-plaintext highlighter-rouge">$("#migrants").selectOption(2);</code></li>
<li><code class="language-plaintext highlighter-rouge">$("#migrants").selectOptionByValue("kill-ducks-from-parks");</code></li>
</ul>
<p>See <a href="https://github.com/selenide/selenide/issues/2832">issue 2832</a> and <a href="https://github.com/selenide/selenide/pull/2835">PR 2835</a>.</p>
<p><br /></p>
<h3 id="builder-methods-for-download-options">Shorter API for downloading files</h3>
<p>To download a “.txt”, you had to write quite a long expression:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">File</span> <span class="n">f</span> <span class="o">=</span> <span class="err">$</span><span class="o">.</span><span class="na">download</span><span class="o">(</span><span class="n">using</span><span class="o">(</span><span class="no">FOLDER</span><span class="o">).</span><span class="na">withFilter</span><span class="o">(</span><span class="n">withExtension</span><span class="o">(</span><span class="s">"txt"</span><span class="o">)));</span>
</code></pre></div></div>
<p>No you can shorten it:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">DownloadOptions</span><span class="o">.</span><span class="na">file</span><span class="o">;</span>
<span class="nc">File</span> <span class="n">f</span> <span class="o">=</span> <span class="err">$</span><span class="o">.</span><span class="na">download</span><span class="o">(</span><span class="n">file</span><span class="o">().</span><span class="na">withExtension</span><span class="o">(</span><span class="s">"txt"</span><span class="o">)));</span>
</code></pre></div></div>
<p>In general, the algorithm is very easy: just write <code class="language-plaintext highlighter-rouge">download(file().</code> - and after the period, available options pop up.</p>
<center>
<img src="/images/2024/09/download-file.png" width="800" />
</center>
<p>See <a href="https://github.com/selenide/selenide/pull/2841">PR 2841</a>.</p>
<p><br /></p>
<h3 id="do-not-close-windows-when-downloading-file">Don’t close windows when downloading files</h3>
<p>Here is the story. <br />
Selenide provides 4 methods for downloading files (HTTPGET, FOLDER, PROXY, CDP), and two of them (FOLDER, PROXY) work
on this principle:</p>
<ol>
<li>Click the link</li>
<li>Wait for the file</li>
<li>If some tabs/windows have been opened after click - close them</li>
<li>Return the file</li>
</ol>
<p>And now we have come to the understanding that the third step is not really necessary.
Nobody even remembers why it was originally added. ¯_(ツ)_/¯</p>
<p>Now Selenide will not even try to close any windows.<br />
If you have a problem with this - contact us, we will discuss the details. :)</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2836">issue 2836</a> and <a href="https://github.com/selenide/selenide/pull/2840">PR 2840</a>.</p>
<p><br /></p>
<h3 id="do-not-catch-all-errors">Don’t catch all Errors anymore</h3>
<p>And again we break the basics. :)<br />
The main <em>algorithm of Selenide</em> is basically a try/catch in a loop (up to 4 seconds timeout).
And here the crucial question: which exception should we catch inside this “try/catch”?</p>
<p>For many years, there was <code class="language-plaintext highlighter-rouge">catch (Error error)</code>. By all accounts, this is bad practice in Java. :)
Nobody remembers exactly why. Maybe it was because of Internet Explorer, which used to throw <code class="language-plaintext highlighter-rouge">java.lang.Error</code> in case of invalid XPath.</p>
<p>The problem is that this <code class="language-plaintext highlighter-rouge">catch (Error error)</code> can hide serious problems, in which the test should not retry in the loop, but immediately fail.
Something like OutOfMemory errors.</p>
<p>Now we don’t catch <code class="language-plaintext highlighter-rouge">Error</code>s anymore and hope that it will not break your tests, because Internet Explorer has long since sunk into oblivion.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2845">PR 2845</a>.</p>
<p><br /></p>
<h3 id="generate-error-details-during-error-construction">Fixed custom error formatters</h3>
<p>Oh, never mind, too lazy to describe it. :)<br />
If you override class <code class="language-plaintext highlighter-rouge">SelenideErrorFormatter</code>,
then read <a href="https://github.com/selenide/selenide/issues/2830">issue 2830</a> and <a href="https://github.com/selenide/selenide/pull/2839">PR 2839</a>.</p>
<p><br /></p>
<h3 id="update-dependencies">Updated dependencies</h3>
<ul>
<li>bump BrowserUpProxy from 2.2.18 to 2.2.19</li>
<li>bump dnsjava from 3.6.0 to 3.6.1</li>
<li>bump LittleProxy from 2.2.4 to 2.3.0 (#2837)</li>
</ul>
<p><br /></p>
<h3 id="news">News</h3>
<ul>
<li>My video <a href="https://www.youtube.com/watch?v=roL1ciaNWtY&list=PL9Z-JgiTsOYRJCXuEOGXLH1w1oImoprnq&ab_channel=ConfEngine">How to migrate from Selenium to Selenide for more stable tests!</a> from SeleniumConf 2024</li>
<li>My video <a href="https://www.youtube.com/watch?v=CKSl2NRrMVg">Selenide: Enjoy Writing Automated Tests for Mobile & Web</a> from Testμ 2024 conference (LambdaTest)</li>
<li>My video <a href="https://www.youtube.com/watch?v=-TvVCxmb9ss&ab_channel=EpicHey">How to debug autotests</a> from EpicHey conference 2023</li>
<li>Post <a href="https://www.testdevlab.com/blog/selenium-or-selenide-which-testing-framework-best-fits-your-needs">Selenium or Selenide: Which Testing Framework Best Fits Your Needs?</a></li>
<li>Post <a href="https://qameta.io/blog/cleaning-up-e2e">Test smells: cleaning up E2E tests</a> by Natalia Poliakova, Mikhail Lankin</li>
<li>Video <a href="https://www.youtube.com/watch?v=j-uaUwoo90k&ab_channel=JoseDiaz">about Selenide in Spanish</a> by Jose Diaz</li>
<li>Video <a href="https://www.youtube.com/watch?v=zDw0iGdSghY&ab_channel=TechProEducationTR">about Selenide in Turkish</a> by Ahmet Bayram Ders</li>
<li>And finally, my video <a href="https://www.youtube.com/watch?v=j-wfc5LVxM4">WTF Commit messages</a>!</li>
</ul>
<p><br /></p>
<h3 id="statistics">Statistics</h3>
<p>Monthly Selenide downloads hit the new record: 1.154.002 in August!</p>
<center>
<img src="/images/2024/09/selenide.downloads.png" width="800" />
</center>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 7.3.12024-04-28T00:00:00+00:00https://selenide.org/2024/04/28/selenide-7.3.1
<p>Good morning!</p>
<p>We released <a href="https://github.com/selenide/selenide/milestone/205?closed=1">Selenide 7.3.1</a>.</p>
<p>It’s a tiny release, so it will be easy to upgrade. Let’s start the unboxing:</p>
<ul>
<li><a href="#mock-specific-content-type">Mock response with specific content type</a></li>
<li><a href="#fix-clear-in-appium">Fixed method <code class="language-plaintext highlighter-rouge">$.clear()</code> in mobile</a></li>
<li><a href="#fix-error-message-for-invalid-link">Fixed error message when clicking an invalid link</a></li>
<li><a href="#disable-warning-about-stolen-password">Disabled Chrome warning about stolen password</a></li>
<li><a href="#fix-cdp-download-for-custom-webdrivers">Fix CDP downloading for custom webdrivers</a></li>
<li><a href="#deprecate-setting-hold-browser-open">Deprecated setting <code class="language-plaintext highlighter-rouge">holdBrowserOpen</code></a></li>
<li><a href="#upgrade-to-selenium-4.20.0">Upgraded Selenium from 4.19.1 to 4.20.0</a></li>
<li><a href="#statistics">Statistics</a></li>
</ul>
<p><br /></p>
<h3 id="mock-specific-content-type">Mock response with specific content type</h3>
<p>As you know, Selenide allows to <a href="/2022/10/07/selenide-6.9.0/#proxy-mock-response">mock server response</a> using its built-in proxy server:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">getSelenideProxy</span><span class="o">().</span><span class="na">responseMocker</span><span class="o">().</span><span class="na">mockText</span><span class="o">(</span><span class="s">"cik-mock"</span><span class="o">,</span>
<span class="n">urlStartsWith</span><span class="o">(</span><span class="no">GET</span><span class="o">,</span> <span class="s">"https://cik.ru/api/gov/no/referendum"</span><span class="o">),</span>
<span class="o">()</span> <span class="o">-></span> <span class="s">"{votes: 2133326, for: 99.23, against: 0.77}"</span><span class="o">);</span>
</code></pre></div></div>
<p>You could specify any response content, <em>but not type</em>. But sometimes the type is important.
Now you can specify any headers for the mocked server response, including <code class="language-plaintext highlighter-rouge">Content-Type</code>:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">org.openqa.selenium.remote.http.HttpResponse</span><span class="o">;</span>
<span class="n">getSelenideProxy</span><span class="o">().</span><span class="na">proxyMocker</span><span class="o">().</span><span class="na">mockResponse</span><span class="o">(</span><span class="s">"cik-mock"</span><span class="o">,</span>
<span class="n">urlStartsWith</span><span class="o">(</span><span class="no">GET</span><span class="o">,</span> <span class="s">"https://cik.ru/api/gov/no/referendum"</span><span class="o">),</span> <span class="o">()</span> <span class="o">-></span> <span class="k">new</span> <span class="nc">HttpResponse</span><span class="o">()</span>
<span class="o">.</span><span class="na">setStatus</span><span class="o">(</span><span class="mi">429</span><span class="o">)</span>
<span class="o">.</span><span class="na">addHeader</span><span class="o">(</span><span class="s">"Content-Type"</span><span class="o">,</span> <span class="s">"application/json"</span><span class="o">)</span>
<span class="o">.</span><span class="na">setContent</span><span class="o">(</span><span class="n">utf8String</span><span class="o">(</span><span class="s">"{votes: 2133326, for: 99.23, against: 0.77}"</span><span class="o">))</span>
<span class="o">);</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/2705">issue 2705</a> and <a href="https://github.com/selenide/selenide/pull/2706">PR 2706</a>.</p>
<p><br /></p>
<h3 id="fix-clear-in-appium">Fixed method <code class="language-plaintext highlighter-rouge">$.clear()</code> in mobile</h3>
<p>… for an element that exists in DOM, but not visible (or interactable).</p>
<p>It turns out that calling <code class="language-plaintext highlighter-rouge">clear</code> or <code class="language-plaintext highlighter-rouge">click</code> on mobile apps:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#hiddenElement"</span><span class="o">).</span><span class="na">clear</span><span class="o">();</span>
</code></pre></div></div>
<p>Failed with an incorrect message if the element is found, but not visible (for example, covered by another element):</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Element</span> <span class="n">should</span> <span class="n">be</span> <span class="n">interactable</span> <span class="o">{</span><span class="nc">By</span><span class="o">.</span><span class="na">name</span><span class="o">:</span> <span class="nc">ComputeSumButton</span><span class="o">}</span>
<span class="nl">Element:</span> <span class="err">'</span><span class="o"><</span><span class="nc">XCUIElementTypeButton</span> <span class="o">...</span> <span class="n">visible</span><span class="o">=</span><span class="s">"false"</span><span class="o">>...</span>
<span class="nc">Caused</span> <span class="nl">by:</span>
<span class="nl">UnsupportedCommandException:</span>
<span class="nc">Unhandled</span> <span class="nl">endpoint:</span> <span class="o">/</span><span class="n">session</span><span class="o">/</span><span class="mi">28</span><span class="o">...</span><span class="mi">13</span><span class="o">/</span><span class="n">element</span><span class="o">/</span><span class="mo">07000000</span><span class="o">-</span><span class="mo">0000</span><span class="o">-</span><span class="mo">0000</span><span class="o">-</span><span class="no">CF35</span><span class="o">-</span><span class="mo">000000000000</span><span class="o">/</span><span class="n">css</span><span class="o">/</span><span class="n">opacity</span> <span class="o">...</span>
</code></pre></div></div>
<p>Now the message will be correct, without any <code class="language-plaintext highlighter-rouge">UnsupportedCommandException</code>:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Element</span> <span class="n">should</span> <span class="n">be</span> <span class="n">visible</span> <span class="o">{</span><span class="nc">By</span><span class="o">.</span><span class="na">name</span><span class="o">:</span> <span class="nc">ComputeSumButton</span><span class="o">}</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/2722">issue 2722</a> and <a href="https://github.com/selenide/selenide/pull/2723">PR 2723</a>.</p>
<p><br /></p>
<h3 id="fix-error-message-for-invalid-link">Fixed error message when clicking an invalid link</h3>
<p>A similar problem. If you try to click an invalid link in Firefox (for example, <code class="language-plaintext highlighter-rouge">https://zopa</code>):</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"#invalid-link"</span><span class="o">)</span>
<span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">attribute</span><span class="o">(</span><span class="s">"href"</span><span class="o">,</span> <span class="s">"https://zopa"</span><span class="o">))</span>
<span class="o">.</span><span class="na">click</span><span class="o">();</span>
</code></pre></div></div>
<p>then Selenide generated an misleading error message:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Element</span> <span class="n">not</span> <span class="n">found</span> <span class="o">{</span><span class="err">#</span><span class="n">link</span><span class="o">}</span>
<span class="nl">Expected:</span> <span class="nl">clickable:</span> <span class="n">interactable</span> <span class="n">and</span> <span class="n">enabled</span>
</code></pre></div></div>
<p>Now there will be an honest error text:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">WebDriverException:</span> <span class="nc">Reached</span> <span class="n">error</span> <span class="nl">page:</span> <span class="nl">about:</span><span class="n">neterror</span><span class="o">?</span><span class="n">e</span><span class="o">=</span><span class="n">dnsNotFound</span><span class="o">&</span><span class="n">u</span><span class="o">=</span><span class="n">https</span><span class="o">%</span><span class="mi">3</span><span class="no">A</span><span class="c1">//zopa/</span>
<span class="nc">Build</span> <span class="nl">info:</span> <span class="nl">version:</span> <span class="err">'</span><span class="mf">4.20</span><span class="o">.</span><span class="mi">0</span><span class="err">'</span><span class="o">,</span> <span class="nl">revision:</span> <span class="err">'</span><span class="mi">866</span><span class="n">c76ca80</span><span class="err">'</span>
</code></pre></div></div>
<p>P.S. Interestingly, only Firefox produces this error. Other browsers calmly display a standard page with a text like this:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>This site can’t be reached
Check if there is a typo in example.
DNS_PROBE_FINISHED_NXDOMAIN
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/2725">issue 2725</a> and <a href="https://github.com/selenide/selenide/pull/2727">PR 2727</a>.</p>
<p><br /></p>
<h3 id="disable-warning-about-stolen-password">Disabled Chrome warning about stolen password</h3>
<p>Again. We already disabled this annoying prompt in <a href="https://github.com/selenide/selenide/pull/2662">PR 2662</a>, but there
we added only setting <code class="language-plaintext highlighter-rouge">profile.password_manager_enabled=false</code> which was not enough. Now we also added
setting <code class="language-plaintext highlighter-rouge">profile.password_manager_leak_detection=false</code>.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2729">PR 2729</a>.</p>
<p><br /></p>
<h3 id="fix-cdp-download-for-custom-webdrivers">Fix CDP downloading for custom webdrivers</h3>
<p>As you remember, few months ago we implemented another file downloading mechanism via CDP.
Obviously, it works only in Chromium-based browsers.</p>
<p>But in case of custom webdrivers, the check “is this a Chromium” didn’t work:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Configuration</span><span class="o">.</span><span class="na">fileDownload</span> <span class="o">=</span> <span class="no">CDP</span><span class="o">;</span>
<span class="nc">Configuration</span><span class="o">.</span><span class="na">browser</span> <span class="o">=</span> <span class="nc">MyCustomChromedriverFactory</span><span class="o">.</span><span class="na">class</span><span class="o">.</span><span class="na">getName</span><span class="o">();</span>
<span class="nc">File</span> <span class="n">report</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#report"</span><span class="o">).</span><span class="na">download</span><span class="o">();</span>
<span class="c1">// threw an error: java.lang.IllegalArgumentException: </span>
<span class="c1">// The browser you selected "MyTest$CustomWebDriverProvider" doesn't have Chrome Devtools protocol functionality.</span>
</code></pre></div></div>
<p>Now Selenide properly detected Chromium-based browser using their actual capabilities.</p>
<p>Thanks <a href="https://github.com/PetroOv">Petr Ovcharenko</a> for <a href="https://github.com/selenide/selenide/pull/2728">PR 2728</a>.</p>
<p><br /></p>
<h3 id="deprecate-setting-hold-browser-open">Deprecated setting <code class="language-plaintext highlighter-rouge">holdBrowserOpen</code></h3>
<p>Selenide has setting <code class="language-plaintext highlighter-rouge">holdBrowserOpen</code>: when set to <code class="language-plaintext highlighter-rouge">true</code>, Selenide will not close the browser after finishing the tests.
Sometimes people want to leave the browser opened to debug/investigate there something.</p>
<p>I personally never liked this feature, and now we’ve got a good reason to remove it.
Suddenly we realized that the feature is harmful. When you finish the debugging and manually close the browser,
nobody closes the webdriver. It will be hanging and consuming resources indefinitely.</p>
<p>Now flag <code class="language-plaintext highlighter-rouge">holdBrowserOpen</code> is deprecated. As a replacement, you can just add <code class="language-plaintext highlighter-rouge">sleep(600_000)</code> in your test - and the browser will stay opened for a long time.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2730">PR 2730</a>.</p>
<p><br /></p>
<h3 id="upgrade-to-selenium-4.20.0">Upgraded Selenium from 4.19.1 to 4.20.0</h3>
<p>I don’t see too much changes in <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">Selenium changelog</a>, so nothing to fear. :)
Among others, they added CDP 124 and removed 121.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2726">PR 2726</a>.</p>
<p><br /></p>
<h3 id="statistics">Statistics</h3>
<p>It happened!!!</p>
<p>The number of monthly downloads of Selenide has exceeded … <strong>a million</strong>!</p>
<center>
<img src="/images/2024/04/selenide.downloads.png" width="600px" />
</center>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 7.2.02024-02-27T00:00:00+00:00https://selenide.org/2024/02/27/selenide-7.2.0
<p>Damn February.</p>
<p>To lift your spirits a bit, try to upgrade to <a href="https://github.com/selenide/selenide/milestone/201?closed=1">Selenide 7.2.0</a>:</p>
<ul>
<li><a href="#download-files-to-folder-in-selenium-grid">Download files from Selenium Grid</a></li>
<li><a href="#download-files-remotely-with-cdp">Download files remotely using CDP</a></li>
<li><a href="#mobile-elements-collections">Collections for mobile tests</a></li>
<li><a href="#disable-chrome-warning-about-stolen-passwords">Disabled chrome warning about stolen password</a></li>
<li><a href="#improve-error-message-for-download-without-href">Error message for element without href</a></li>
<li><a href="#upgraded-to-selenium-4.18.1">Updated Selenium from 4.17.0 to 4.18.1</a></li>
</ul>
<p><br /></p>
<h3 id="download-files-to-folder-in-selenium-grid">Download files from Selenium Grid</h3>
<p>Finally! <br />
Now you can download using <code class="language-plaintext highlighter-rouge">FOLDER</code> method from Selenium Grid.<br />
Until now, <code class="language-plaintext highlighter-rouge">FOLDER</code> only worked for local browsers and Selenoid.</p>
<p>If you run tests in Selenium Grid and need to download files with <code class="language-plaintext highlighter-rouge">FOLDER</code> method, you just need to replace dependency</p>
<div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">:</span><span class="nl">selenide:</span><span class="mf">7.1</span><span class="o">.</span><span class="mi">0</span>
</code></pre></div></div>
<p>by</p>
<div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">:</span><span class="n">selenide</span><span class="o">-</span><span class="nl">grid:</span><span class="mf">7.2</span><span class="o">.</span><span class="mi">0</span>
</code></pre></div></div>
<p>And that’s basically it.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Configuration</span><span class="o">.</span><span class="na">remote</span> <span class="o">=</span> <span class="s">"https://qa.grid.my.com:4444/wd/hub"</span><span class="o">;</span>
<span class="nc">Configuration</span><span class="o">.</span><span class="na">fileDownload</span> <span class="o">=</span> <span class="no">FOLDER</span><span class="o">;</span>
<span class="nc">File</span> <span class="n">quotes</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#quotes"</span><span class="o">).</span><span class="na">download</span><span class="o">(</span><span class="n">withExtension</span><span class="o">(</span><span class="s">"txt"</span><span class="o">));</span>
<span class="n">assertThat</span><span class="o">(</span><span class="n">quotes</span><span class="o">.</span><span class="na">content</span><span class="o">()).</span><span class="na">contains</span><span class="o">(</span>
<span class="s">"Love is stronger than fear"</span><span class="o">,</span>
<span class="s">"It's a shame to do nothing, it's a shame to allow yourself to be intimidated."</span><span class="o">);</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/1687">issue 1687</a>,
<a href="https://github.com/selenide/selenide/pull/2659">PR 2659</a> and <a href="https://github.com/selenide/selenide/pull/2660">PR 2660</a>.</p>
<p><br /></p>
<h3 id="download-files-remotely-with-cdp">Download files remotely using CDP</h3>
<p>In the previous release, we added method <a href="/2024/02/07/selenide-7.1.0/#download-files-with-cdp">CDP</a> for downloading files.
But it worked only for local browsers.</p>
<p>Now it also works with remote browsers running on Selenoid or Selenium Grid.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Configuration</span><span class="o">.</span><span class="na">remote</span> <span class="o">=</span> <span class="s">"https://cloud.browsers.my.com:4444/wd/hub"</span><span class="o">;</span>
<span class="nc">Configuration</span><span class="o">.</span><span class="na">fileDownload</span> <span class="o">=</span> <span class="no">CDP</span><span class="o">;</span>
<span class="nc">File</span> <span class="n">places</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#places"</span><span class="o">).</span><span class="na">download</span><span class="o">(</span><span class="n">withExtension</span><span class="o">(</span><span class="s">"csv"</span><span class="o">));</span>
<span class="n">assertThat</span><span class="o">(</span><span class="n">places</span><span class="o">.</span><span class="na">content</span><span class="o">()).</span><span class="na">contains</span><span class="o">(</span><span class="s">"Church of the Icon of the Mother of God"</span><span class="o">,</span> <span class="s">"Borisovskoye"</span><span class="o">);</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/1687">issue 1687</a>, <a href="https://github.com/selenide/selenide/issues/2550">issue 2550</a>
and <a href="https://github.com/selenide/selenide/pull/2661">PR 2661</a>.</p>
<p><br /></p>
<h3 id="mobile-elements-collections">Collections for mobile tests</h3>
<p>We have piled up useful things for testing mobile applications. There are new methods for collections:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">SelenideAppium.$$(By)</code></li>
<li><code class="language-plaintext highlighter-rouge">SelenideAppium.$$(Collection<WebElement>)</code></li>
</ul>
<p>Both return an instance of <code class="language-plaintext highlighter-rouge">SelenideAppiumCollection</code>.
This is basically the same as the old good <code class="language-plaintext highlighter-rouge">ElementsCollection</code>, but with <code class="language-plaintext highlighter-rouge">SelenideAppiumElement</code> instances instead of <code class="language-plaintext highlighter-rouge">SelenideElement</code>.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">SelenideAppiumCollection</span> <span class="n">poetry</span> <span class="o">=</span> <span class="err">$$</span><span class="o">(</span><span class="nc">By</span><span class="o">.</span><span class="na">xpath</span><span class="o">(</span><span class="s">"//android.widget.EditText"</span><span class="o">)).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">size</span><span class="o">(</span><span class="mi">2</span><span class="o">));</span>
<span class="n">poetry</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="mi">0</span><span class="o">).</span><span class="na">scroll</span><span class="o">(</span><span class="n">up</span><span class="o">()).</span><span class="na">setValue</span><span class="o">(</span><span class="s">"and blood clots will fall into the sky"</span><span class="o">);</span>
<span class="n">poetry</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="mi">1</span><span class="o">).</span><span class="na">scroll</span><span class="o">(</span><span class="n">down</span><span class="o">()).</span><span class="na">setValue</span><span class="o">(</span><span class="s">"of crimson Kremlin towers"</span><span class="o">);</span>
</code></pre></div></div>
<p>Also, we added method <code class="language-plaintext highlighter-rouge">SelenideAppium.$(WebElement webElement)</code>, but it’s unlikely to be useful to you.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2333">issue 2333</a> and <a href="https://github.com/selenide/selenide/pull/2656">PR 2656</a>.</p>
<p><br /></p>
<h3 id="disable-chrome-warning-about-stolen-passwords">Disabled chrome warning about stolen password</h3>
<p>After updating Chrome, this annoying dialog “The password… was found in a data breach” started popping up.
It seems logical that nobody needs this popup in the tests.</p>
<p>Although this looks more like a Chrome 122 bug, we quickly disabled this popup - just in case.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2658">issue 2658</a> and <a href="https://github.com/selenide/selenide/pull/2662">PR 2662</a>.</p>
<p><br /></p>
<h3 id="improve-error-message-for-download-without-href">Error message for element without <code class="language-plaintext highlighter-rouge">href</code></h3>
<p>I suddenly realized why so many people struggle with setting up a proxy, and don’t even realize that Selenide has easier
methods for downloading files: <code class="language-plaintext highlighter-rouge">FOLDER</code> and <code class="language-plaintext highlighter-rouge">CDP</code>.</p>
<p>Well, the problem might be in communication. All these years, method <code class="language-plaintext highlighter-rouge">$.download()</code> threw the following error message:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">The</span> <span class="n">element</span> <span class="n">does</span> <span class="n">not</span> <span class="n">have</span> <span class="n">href</span> <span class="nl">attribute:</span> <span class="o"><</span><span class="n">a</span> <span class="n">id</span><span class="o">=</span><span class="s">"generate-report"</span><span class="o">></span>
</code></pre></div></div>
<p>Seeing this message, people opened the <a href="https://selenide.org/2019/12/10/advent-calendar-download-files/">first post from Google</a> - which
is 5 years old and mentioned only one alternative - <code class="language-plaintext highlighter-rouge">PROXY</code>. And they rushed to study the proxy.</p>
<p>Now the error message will indicate that there are multiple downloading methods:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">The</span> <span class="n">element</span> <span class="n">does</span> <span class="n">not</span> <span class="n">have</span> <span class="s">"href"</span> <span class="nl">attribute:</span> <span class="o"><</span><span class="n">a</span> <span class="n">id</span><span class="o">=</span><span class="s">"generate-report"</span><span class="o">>,</span> <span class="n">so</span> <span class="n">method</span> <span class="no">HTTPGET</span> <span class="n">cannot</span> <span class="n">download</span> <span class="n">the</span> <span class="n">file</span><span class="o">.</span>
<span class="nc">Please</span> <span class="k">try</span> <span class="n">another</span> <span class="n">download</span> <span class="nl">method:</span> <span class="no">FOLDER</span><span class="o">,</span> <span class="no">CDP</span> <span class="n">or</span> <span class="no">PROXY</span><span class="o">.</span>
<span class="nc">Read</span> <span class="n">more</span> <span class="n">about</span> <span class="n">possible</span> <span class="n">download</span> <span class="nl">methods:</span> <span class="nl">https:</span><span class="c1">//selenide.org/javadoc/current/com/codeborne/selenide/FileDownloadMode.html</span>
</code></pre></div></div>
<p>However, I’m afraid this won’t help, because who reads them…</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2653">PR 2653</a>.</p>
<p><br /></p>
<h3 id="upgraded-to-selenium-4.18.1">Updated Selenium from 4.17.0 to 4.18.1</h3>
<p>See <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">Selenium changelog</a> and
<a href="https://github.com/selenide/selenide/pull/2655">PR 2655</a>.</p>
<p><br /></p>
<p>Let’s hope for spring.</p>
<p><br /></p>
<blockquote>
<p>You’re not allowed to give up.<br />
Don’t be discouraged and don’t give up.<br />
Test automation is not a sprint, but a long and hard marathon.</p>
</blockquote>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 7.1.02024-02-07T00:00:00+00:00https://selenide.org/2024/02/07/selenide-7.1.0
<p>Good evening!
Happy New Year, happy new hopes!</p>
<p>Today we have a fresh shiny <a href="https://github.com/selenide/selenide/milestone/199?closed=1">Selenide 7.1.0</a> one on the menu:</p>
<ul>
<li><a href="#download-files-with-cdp">Download files with CDP</a></li>
<li><a href="#animated-condition">Condition <code class="language-plaintext highlighter-rouge">animated</code></a></li>
<li><a href="#if-with-timeout">IF with timeout ¯¯_(ツ)_/¯¯</a></li>
<li><a href="#force-click">Click disabled elements</a></li>
<li><a href="#method-unfocus">New method <code class="language-plaintext highlighter-rouge">$.unfocus()</code></a></li>
<li><a href="#avoid-page-load-timeout-in-mobile">Fixed page load timeout in mobile tests</a></li>
<li><a href="#can-add-same-proxy-filter-many-times">Add same proxy filter many times</a></li>
<li><a href="#update-dependencies">Updated dependencies</a></li>
<li><a href="#statistics">Statistics</a></li>
</ul>
<p><br /></p>
<h3 id="download-files-with-cdp">Download files with CDP</h3>
<p>Less than three years have passed since CDP was introduced into Selenium, and we have already downloaded files using it!
As you know, there are several ways to download files in Selenide: <code class="language-plaintext highlighter-rouge">HTTPGET</code>, <code class="language-plaintext highlighter-rouge">FOLDER</code>, <code class="language-plaintext highlighter-rouge">PROXY</code>.
Now <code class="language-plaintext highlighter-rouge">CDP</code> has been added to them:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Configuration</span><span class="o">.</span><span class="na">fileDownload</span> <span class="o">=</span> <span class="no">CDP</span><span class="o">;</span>
<span class="nc">File</span> <span class="n">f</span> <span class="o">=</span> <span class="err">$</span><span class="o">.</span><span class="na">download</span><span class="o">();</span>
</code></pre></div></div>
<p>or</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">File</span> <span class="n">f</span> <span class="o">=</span> <span class="err">$</span><span class="o">.</span><span class="na">download</span><span class="o">(</span><span class="n">using</span><span class="o">(</span><span class="no">CDP</span><span class="o">));</span>
</code></pre></div></div>
<p>It works similarly to <code class="language-plaintext highlighter-rouge">FOLDER</code>: clicks the link and waits for the file to appear in the list of downloaded files.
Only unlike <code class="language-plaintext highlighter-rouge">FOLDER</code>, <code class="language-plaintext highlighter-rouge">CDP</code> understands that the download is complete not by the file date, but by the <code class="language-plaintext highlighter-rouge">Browser.downloadProgress</code> event from the CDP.</p>
<p>Of course, this download method only works in Chromium browsers. And only on a local browser for now.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2550">issue 2550</a>.
Thanks to <a href="https://github.com/britka">Sergey Brit</a> for <a href="https://github.com/selenide/selenide/pull/2567">PR 2567</a>.</p>
<hr />
<p>NB! As a contributor, Sergey gets the right to tell you about a fund of his choice.</p>
<p>Word to Sergei:</p>
<blockquote>
<p>I encourage you to donate to the fund <a href="https://www.angrycorgi.org/en">ANGRY CORGI</a>.</p>
<p>Angry Corgi is a charity run by tech folks from local Ukrainian companies. <br />
Folks are aiming to ensure Air Defense computer infrastructure is sufficient to defend the military personnel and
civilians from russian forces attacks. Their teams permanently collects laptops from people across the world and
fundraises to purchase new tablets, TV sets and other network equipment for the units.</p>
</blockquote>
<p>This is what we will now have as a glorious tradition. :)</p>
<hr />
<p><br /></p>
<h3 id="animated-condition">Condition <code class="language-plaintext highlighter-rouge">animated</code> for waiting for the completion of an animation</h3>
<p>Animated elements can cause a lot of unpleasant moments for QA engineers. Your test tries to click an element - but
at this moment the element is moving, resizing, shrinking, expanding - what the hell. And the click hits another element.</p>
<blockquote>
<p>More about animation in my video <a href="https://www.youtube.com/watch?v=18J2_4a4Cl4&ab_channel=Jfokus&t=24m08s">Flaky tests</a>.</p>
</blockquote>
<p>Now you can wait for the completion of animation using this command:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">.</span><span class="na">shouldNotBe</span><span class="o">(</span><span class="n">animated</span><span class="o">);</span>
</code></pre></div></div>
<p>We hope this helps make your tests more stable.</p>
<p>Thanks to <a href="https://github.com/BorisOsipov">Boris Osipov</a> for <a href="https://github.com/selenide/selenide/pull/2556/files">PR 2556</a>.</p>
<p>You may ask, how does selenide understand that the animation has ended? Take a look at the pull request, it’s interesting.
In short, using the JS function <code class="language-plaintext highlighter-rouge">requestAnimationFrame</code>, selenide asks the browser for dimensions and coordinates of the
element twice in a row (in two different rendering cycles), and checks that they have not changed. Tricky, huh?</p>
<p><br /></p>
<h3 id="if-with-timeout">Added IF with timeout ¯¯_(ツ)_/¯¯</h3>
<p>We resisted for many years, but finally we allowed it to happen. :)</p>
<p>We added method <code class="language-plaintext highlighter-rouge">$.is(condition, timeout)</code> that returns boolean. Now in your tests you can write IFs without try/catch.
<a href="/2019/12/02/advent-calendar-how-to-abuse-selenide/">The gates to hell have opened</a>.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">if</span> <span class="o">(</span><span class="err">$</span><span class="o">(</span><span class="s">"#banner"</span><span class="o">).</span><span class="na">is</span><span class="o">(</span><span class="n">visible</span><span class="o">,</span> <span class="nc">Duration</span><span class="o">.</span><span class="na">ofSeconds</span><span class="o">(</span><span class="mi">2</span><span class="o">)))</span> <span class="o">{</span>
<span class="err">$</span><span class="o">(</span><span class="s">"#banner .close"</span><span class="o">).</span><span class="na">click</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div></div>
<p>For sure, the logic of this IF will explode many brains, so read carefully:</p>
<ol>
<li>If the element is visible, it will <em>immediately</em> return <code class="language-plaintext highlighter-rouge">true</code>.</li>
<li>If the element is not visible, the method will wait for some time (but no more than given timeout), and if the element has appeared - will return <code class="language-plaintext highlighter-rouge">true</code>.</li>
<li>And only if the element still hasn’t appeared after the timeout, it will return <code class="language-plaintext highlighter-rouge">false</code>.</li>
</ol>
<p>See <a href="https://github.com/selenide/selenide/issues/2590">issue 2590</a>.<br />
Eternal shame on <a href="https://github.com/asolntsev">my gray hairs</a> for <a href="https://github.com/selenide/selenide/pull/2640">PR 2640</a>!</p>
<blockquote>
<p>NB! New method <code class="language-plaintext highlighter-rouge">$.is(.., Duration.ofSeconds(8))</code> <em>can be slow</em>! In case of <code class="language-plaintext highlighter-rouge">false</code> result, it will always take <em>8 seconds</em>!
This is a deadly long time for tests. Please avoid such checks.</p>
</blockquote>
<p><br /></p>
<h3 id="force-click">You can click disabled elements</h3>
<p>Starting from version 6.15.0, Selenide <a href="/2023/05/29/selenide-6.15.0/#clicking-disable-element-fails">doesn’t allow clicking disabled elements</a>.
But sometimes it might be needed (for example, ti check that clicking on such an element has no effect).
Now you can bypass all checks and simply click on any element using the <code class="language-plaintext highlighter-rouge">force</code> parameter:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"#disabledButton"</span><span class="o">).</span><span class="na">click</span><span class="o">(</span><span class="n">usingDefaultMethod</span><span class="o">().</span><span class="na">force</span><span class="o">());</span>
</code></pre></div></div>
<p>Don’t overuse it.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2635">issue 2635</a> and <a href="https://github.com/selenide/selenide/pull/2636">PR 2636</a>.</p>
<p><br /></p>
<h3 id="method-unfocus">New method <code class="language-plaintext highlighter-rouge">$.unfocus()</code></h3>
<p>We added method <code class="language-plaintext highlighter-rouge">$.unfocus()</code> that removes focus from an element.</p>
<p>In fact, you could do it using method <code class="language-plaintext highlighter-rouge">$.pressTab()</code>, but it may have unwanted side effects.
For example, another element suddenly could get focused.
And sometimes, by pressing TAB, the form could be submitted altogether (for example, when entering an OTP code).</p>
<p>In that sense the new method <code class="language-plaintext highlighter-rouge">$.unfocus()</code> is safe: it just removes the focus from the element without focusing any other element.<br />
Thus you can check the work of autocompletion, auto-formatting, hints, popups etc.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"#card-number"</span><span class="o">).</span><span class="na">sendKeys</span><span class="o">(</span><span class="s">"1111-222-33-4444"</span><span class="o">).</span><span class="na">unfocus</span><span class="o">();</span>
<span class="err">$</span><span class="o">(</span><span class="s">"#preview"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Pay to 1111-***-**-***4 ?"</span><span class="o">));</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/2638">issue 2638</a> and <a href="https://github.com/selenide/selenide/pull/2639">PR 2639</a>.</p>
<p><br /></p>
<h3 id="avoid-page-load-timeout-in-mobile">Fixed page load timeout in mobile tests</h3>
<p>Selenide had a bug: it occasionally set property <code class="language-plaintext highlighter-rouge">Configuration.pageLoadTimeout</code> to 0 in mobile tests.
But Appium doesn’t support such a setting. That’s why you could see these warnings in logs:</p>
<blockquote>
<p>NotImplementedError: Not implemented yet for pageLoad</p>
</blockquote>
<p>It’s not critical, it’s just a warning. Nevertheless, now we fixed it.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2612">issue 2612</a> and <a href="https://github.com/selenide/selenide/pull/2628">PR 2628</a>.</p>
<p><br /></p>
<h3 id="can-add-same-proxy-filter-many-times">Add same proxy filter many times</h3>
<p>It has become a little easier to add your own filters for the Selenide proxy.
Now you don’t have to check that such a filter has already been added earlier, but simply add it again each time:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">RequestFilter</span> <span class="no">REQUEST_LOGGER</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">RequestFilter</span><span class="o">()</span> <span class="o">{...}</span>
<span class="nd">@BeforeEach</span>
<span class="kd">final</span> <span class="kt">void</span> <span class="nf">setUp</span><span class="o">()</span> <span class="o">{</span>
<span class="n">getSelenideProxy</span><span class="o">().</span><span class="na">addRequestFilter</span><span class="o">(</span><span class="s">"request-logger"</span><span class="o">,</span> <span class="no">REQUEST_LOGGER</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Previously, Selenide complained that such filter already exists. And now it will continue to work calmly (but only if it is really the same filter).</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2617">issue 2617</a> and <a href="https://github.com/selenide/selenide/pull/2630">PR 2630</a>.</p>
<p><br /></p>
<h3 id="update-dependencies">Updated dependencies</h3>
<ul>
<li>bump JUnit from 5.10.1 to 5.10.2</li>
<li>bump TestNG from 7.8.0 to 7.9.0</li>
<li>Bump slf4jVersion from 2.0.11 to 2.0.12</li>
<li>Bump LittleProxy from 2.1.1 to 2.1.2</li>
</ul>
<p><br /></p>
<h3 id="statistics">Statistics</h3>
<p>The number of monthly downloads of Selenide has exceeded 911 thousand!</p>
<center>
<img src="/images/2024/01/selenide.downloads.png" width="600px" />
</center>
<p>Wow.</p>
<p>And another interesting figure.</p>
<p>Selenide has one subproject <a href="https://github.com/selenide/selenide/tree/main/modules/appium"><code class="language-plaintext highlighter-rouge">selenide-appium</code></a> for writing autotests for mobile phones. He didn’t use it much before
in demand (compared to Selenide itself), but this year it has sharply increased.</p>
<center>
<img src="/images/2024/01/selenide-appium.downloads.png" width="600px" />
</center>
<p>I don’t know why this happens, but it’s cool. :)</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 7.0.12023-10-26T00:00:00+00:00https://selenide.org/2023/10/26/selenide-7.0.1
<p>Yesterday we released <a href="/2023/10/25/selenide-7.0.0/">Selenide 7.0.0</a>. I expected complains about Java 17, but…</p>
<p>no. Nobody complained about Java 17. And that’s great! <br />
But people asked to restore loops over collections.</p>
<p>Well, in today update <a href="https://github.com/selenide/selenide/milestone/194?closed=1">Selenide 7.0.1</a> we restored a couple of things:</p>
<ul>
<li><a href="#restore-collection-loop">Restore loops over collections</a></li>
<li><a href="#restore-collection-is-empty">Restore method <code class="language-plaintext highlighter-rouge">isEmpty()</code> for collections</a></li>
<li><a href="#restore-self-in-containers">Return field <code class="language-plaintext highlighter-rouge">self</code> in containers</a></li>
<li><a href="#rename-collection-condition">Renamed <code class="language-plaintext highlighter-rouge">CollectionCondition</code> to <code class="language-plaintext highlighter-rouge">WebElementsCondition</code></a></li>
<li><a href="#upgrade-to-selenium-4.15.0">UPD 7.0.2: Upgraded to Selenium 4.15.0</a></li>
</ul>
<p><br /></p>
<h3 id="restore-collection-loop">Restore loops over collections</h3>
<p>Now you can use <code class="language-plaintext highlighter-rouge">for</code> loop again:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="o">(</span><span class="nc">SelenideElement</span> <span class="n">element</span> <span class="o">:</span> <span class="err">$$</span><span class="o">(</span><span class="s">".element"</span><span class="o">))</span> <span class="o">{</span>
<span class="n">element</span><span class="o">.</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">visible</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>
<p>And I won’t tire of repeating that</p>
<blockquote>
<p>DON’T DO IT!</p>
</blockquote>
<p><a href="https://github.com/selenide/selenide/wiki/do-not-use-getters-in-tests">Don’t use loops and ifs in tests!</a></p>
<p>If you want to collect the texts/attributes of all elements to check them - Selenide has “collection conditions” for that:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$$</span><span class="o">(</span><span class="s">".errors"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">texts</span><span class="o">(</span><span class="s">"One"</span><span class="o">,</span> <span class="s">"Two"</span><span class="o">,</span> <span class="s">"Three"</span><span class="o">));</span>
<span class="err">$$</span><span class="o">(</span><span class="s">"#numbers option"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">attributes</span><span class="o">(</span><span class="s">"value"</span><span class="o">,</span>
<span class="s">"one"</span><span class="o">,</span> <span class="s">"two"</span><span class="o">,</span> <span class="s">"three"</span><span class="o">,</span> <span class="s">"four"</span><span class="o">,</span> <span class="s">"five"</span><span class="o">));</span>
</code></pre></div></div>
<p>If you haven’t found a suitable check for your needs, you can easily create your own <a href="https://github.com/selenide/selenide/wiki/Custom-collection-conditions">custom condition</a>.
Just create a class inheriting <code class="language-plaintext highlighter-rouge">WebElementsCondition</code> and implement method <code class="language-plaintext highlighter-rouge">check</code>. That’s easy. <br />
And you can reuse it in all your tests.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2533">PR 2533</a>.</p>
<p><br /></p>
<h3 id="restore-collection-is-empty">Restore method <code class="language-plaintext highlighter-rouge">isEmpty()</code> for collections</h3>
<p>I still understand why, but people do you this method:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kt">boolean</span> <span class="n">errorsFound</span> <span class="o">=</span> <span class="err">$$</span><span class="o">(</span><span class="s">".error"</span><span class="o">).</span><span class="na">isEmpty</span><span class="o">();</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/pull/2533">PR 2533</a>.</p>
<p><br /></p>
<h3 id="restore-self-in-containers">Return field <code class="language-plaintext highlighter-rouge">self</code> in containers</h3>
<p>In release 7.0.0, we removed class <code class="language-plaintext highlighter-rouge">ElementsContainer</code>. With this, you lost method <code class="language-plaintext highlighter-rouge">getSelf()</code>.
I still find it strange, but people do you this method as well.</p>
<p>If this sounds like you, then you can replace the <code class="language-plaintext highlighter-rouge">getSelf()</code> method with a field annotated by <code class="language-plaintext highlighter-rouge">@Self</code>:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">static</span> <span class="kd">class</span> <span class="nc">RadioButton</span> <span class="kd">implements</span> <span class="nc">Container</span> <span class="o">{</span>
<span class="nd">@Self</span>
<span class="nc">SelenideElement</span> <span class="n">label</span><span class="o">;</span>
<span class="nd">@FindBy</span><span class="o">(</span><span class="n">tagName</span> <span class="o">=</span> <span class="s">"input[type=radio]"</span><span class="o">)</span>
<span class="nc">SelenideElement</span> <span class="n">input</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/pull/2534">PR 2534</a>.</p>
<p><br /></p>
<h3 id="rename-collection-condition">Renamed <code class="language-plaintext highlighter-rouge">CollectionCondition</code> to <code class="language-plaintext highlighter-rouge">WebElementsCondition</code></h3>
<p>It affects you only if you have <a href="https://github.com/selenide/selenide/wiki/Custom-collection-conditions">custom collection conditions</a>.</p>
<p>Not a problem. Just replace <code class="language-plaintext highlighter-rouge">extends CollectionCondition</code> by <code class="language-plaintext highlighter-rouge">WebElementsCondition</code>.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2372">issue 2372</a> and <a href="https://github.com/selenide/selenide/pull/2533">PR 2533</a>.</p>
<p><br /></p>
<h3 id="upgrade-to-selenium-4.15.0">UPD 7.0.2: Upgraded to Selenium 4.15.0</h3>
<p>We released Selenide 7.0.2 with upgrade to the latest Selenium 4.15.0.</p>
<p>Here is Selenium <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">changelog</a>.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2540">PR 2540</a>.</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 7.0.02023-10-25T00:00:00+00:00https://selenide.org/2023/10/25/selenide-7.0.0
<p>Happy birthday!</p>
<p>Today is October 25.
Today, 12 years ago the first commit in the Selenide project was created.</p>
<p>For the holiday, we released a major release <a href="https://github.com/selenide/selenide/milestone/191?closed=1">Selenide 7.0.0</a>
with the update immediately to Java 17.</p>
<ul>
<li><a href="#java17">Updated to Java 17</a></li>
<li><a href="#update-dependencies">Updated dependencies</a></li>
<li><a href="#fix-deadlock-in-static-initialization">Static initialization deadlock</a></li>
<li><a href="#report-actual-value-at-the-moment-of-check">Actual value at the moment of check</a></li>
<li><a href="#remove-deprecated-condition-methods">Removed deprecated methods in <code class="language-plaintext highlighter-rouge">Condition</code></a></li>
<li><a href="#remove-deprecated-methods-from-collection-conditions">Removed deprecated methods in <code class="language-plaintext highlighter-rouge">CollectionCondition</code></a></li>
<li><a href="#remove-deprecated-methods-from-elements-collection">Removed deprecated methods in <code class="language-plaintext highlighter-rouge">ElementsCollection</code></a></li>
<li><a href="#replace-elements-container-by-container">Replaced deprecated <code class="language-plaintext highlighter-rouge">ElementsContainer</code> by <code class="language-plaintext highlighter-rouge">Container</code></a></li>
<li><a href="#replace-file-not-found-exception">Replaced <code class="language-plaintext highlighter-rouge">FileNotFoundException</code> by <code class="language-plaintext highlighter-rouge">FileNotDownloadedError</code></a></li>
<li><a href="#rename-exceptions-to-errors">Renamed <code class="language-plaintext highlighter-rouge">*Exception</code> to <code class="language-plaintext highlighter-rouge">*Error</code></a></li>
<li><a href="#remove-deprecated-listener">Removed support for deprecated <code class="language-plaintext highlighter-rouge">WebDriverEventListener</code></a></li>
<li><a href="#remove-deprecated-drag-and-drop-methods">Removed deprecated Drag’n’drop methods</a></li>
<li><a href="#remove-deprecated-get-selected-value-methods">Removed deprecated methods <code class="language-plaintext highlighter-rouge">$.getSelectedValue()</code> and <code class="language-plaintext highlighter-rouge">$.getSelectedText()</code></a></li>
<li><a href="#remove-deprecated-testng-annotations">Removed deprecated TestNG annotations <code class="language-plaintext highlighter-rouge">@Report</code> and <code class="language-plaintext highlighter-rouge">@GlobalTextReport</code></a></li>
<li><a href="#remove-other-deprecated-methods">Other cleanup</a></li>
</ul>
<p><br /></p>
<h3 id="java17">Updated to Java 17</h3>
<p>Wow!<br />
This day came!</p>
<p>To use Selenide 7.+, you will need to compile & run your tests with Java 17+.</p>
<p>How cool is that, right?</p>
<p>I know some of you don’t like this decision. You are still forced to run tests on Java 8.</p>
<p>But we are not guilty. As you know, Selenium 4.14+ upgraded from Java 8 to Java 11.
So it was not possible to stay on Java 8 anyway. You have to update to Java 11 at least.</p>
<p>Now, there is a very simple reasoning. In any Java project, the most complex update is from Java 8 to Java 11.
Compared to this, updating from Java 11 to Java 17 is much more simple. There is nothing to do there, really.</p>
<p>So just update your Java!</p>
<blockquote>
<p>Life is too short to continue fiddling with Java 8</p>
</blockquote>
<p>See <a href="https://github.com/selenide/selenide/pull/2522">PR 2522</a>.</p>
<p><br /></p>
<h3 id="update-dependencies">Updated dependencies</h3>
<ul>
<li>Updated Selenium from 4.13.0 to 4.14.1 (<a href="https://github.com/selenide/selenide/pull/2505">PR 2505</a>) <small>- requires Java 11+</small></li>
<li>Updated Appium from 8.6.0 to 9.0.0 (<a href="https://github.com/selenide/selenide/pull/2505">PR 2505</a>) <small>- requires Java 11+</small></li>
<li>Updated TestNG from 7.4.0 to 7.8.0 (<a href="https://github.com/selenide/selenide/pull/2515">PR 2505</a>) <small>- requires Java 11+</small></li>
</ul>
<p><br /></p>
<h3 id="fix-deadlock-in-static-initialization">Fixed static initialization deadlock</h3>
<p>This was an old potential problem in Selenide: class <code class="language-plaintext highlighter-rouge">Condition</code> and any of its subclasses depended on each other.<br />
Therefore, under certain circumstances, a deadlock could occur when these classes were loaded simultaneously.
Very unlikely, but theoretically possible.</p>
<blockquote>
<p>More details about <a href="https://blog.palantir.com/using-static-analysis-to-prevent-java-class-initialization-deadlocks-c2f31ca967d6">static initialization deadlock</a>.</p>
</blockquote>
<p>To fix the problem, we had to rename the base class <code class="language-plaintext highlighter-rouge">Condition</code> to <code class="language-plaintext highlighter-rouge">WebElementCondition</code>.</p>
<ol>
<li>Don’t worry, all your <code class="language-plaintext highlighter-rouge">Condition.visible</code> imports will remain unchanged.</li>
<li>But if you have custom conditions, you will need to replace <code class="language-plaintext highlighter-rouge">extends Condition</code> by <code class="language-plaintext highlighter-rouge">extends WebElementCondition</code>.</li>
</ol>
<p>See <a href="https://github.com/selenide/selenide/issues/2372">issue 2372</a> and <a href="https://github.com/selenide/selenide/pull/2453">PR 2453</a>.</p>
<p><br /></p>
<h3 id="report-actual-value-at-the-moment-of-check">Actual value at the moment of check</h3>
<p>Here we are talking not about web elements’ checks, but <a href="/2021/07/16/selenide-5.23.0/">“new generation” checks</a>: url, localStorage etc.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">webdriver</span><span class="o">().</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">url</span><span class="o">(</span><span class="s">"https://some.com/page.html"</span><span class="o">));</span>
<span class="n">localStorage</span><span class="o">().</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">item</span><span class="o">(</span><span class="s">"mouse"</span><span class="o">,</span> <span class="s">"Jerry”));
sessionStorage().shouldHave(itemWithValue("</span><span class="n">mouse</span><span class="s">", "</span><span class="nc">Jerry</span><span class="err">”</span><span class="o">));</span>
<span class="n">clipboard</span><span class="o">().</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">content</span><span class="o">(</span><span class="s">"Remember me"</span><span class="o">));</span>
</code></pre></div></div>
<p>Shortly, we made the error message in these checks more correct.
Find details in <a href="https://github.com/selenide/selenide/issues/2500">issue 2500</a> and <a href="https://github.com/selenide/selenide/pull/2501">PR 2501</a>.</p>
<p><br /></p>
<h3 id="remove-deprecated-condition-methods">Removed deprecated methods in <code class="language-plaintext highlighter-rouge">Condition</code></h3>
<p>Removed deprecated methods <code class="language-plaintext highlighter-rouge">apply()</code> and <code class="language-plaintext highlighter-rouge">actualValue()</code> in class <code class="language-plaintext highlighter-rouge">Condition</code>.</p>
<p>This will only affect you if you wrote your own custom checks.
Now, instead of two methods <code class="language-plaintext highlighter-rouge">apply()</code> and <code class="language-plaintext highlighter-rouge">actualValue()</code>, you will need to implement only one method <code class="language-plaintext highlighter-rouge">check</code>.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2512">PR 2512</a>.</p>
<p><br /></p>
<h3 id="remove-deprecated-methods-from-collection-conditions">Removed deprecated methods in <code class="language-plaintext highlighter-rouge">CollectionCondition</code></h3>
<p>Similarly to the previous change, it only affects you if you have custom checks for collections (<code class="language-plaintext highlighter-rouge">extends CollectionCondition</code>).
Instead of two methods <code class="language-plaintext highlighter-rouge">test</code> and <code class="language-plaintext highlighter-rouge">fail</code>, you need to implement only one method <code class="language-plaintext highlighter-rouge">check</code>.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2520">PR 2520</a>.</p>
<p><br /></p>
<h3 id="remove-deprecated-methods-from-elements-collection">Removed deprecated methods in <code class="language-plaintext highlighter-rouge">ElementsCollection</code></h3>
<p>Be prepared for the shock.<br />
Class <code class="language-plaintext highlighter-rouge">ElementsCollection</code> does <strong>not extend</strong> <code class="language-plaintext highlighter-rouge">java.util.List</code> anymore.
From the very beginning, this inheritance <em>occasionally</em> added to <code class="language-plaintext highlighter-rouge">ElementsCollection</code> many unneeded methods
(like <code class="language-plaintext highlighter-rouge">remove()</code>, <code class="language-plaintext highlighter-rouge">removeRange</code>, <code class="language-plaintext highlighter-rouge">clear</code>, <code class="language-plaintext highlighter-rouge">subList</code> and <code class="language-plaintext highlighter-rouge">listIterator()</code>) that we never intended to implement.<br />
But users sometimes did use them. And even complained that these methods didn’t work.</p>
<p>Now we don’t have these methods and don’t have these problems. <br />
Now <code class="language-plaintext highlighter-rouge">$$</code> has only the methods we find useful. Amen.</p>
<p>P.S. If you have a loop over collection elements:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">for</span> <span class="o">(</span><span class="nc">SelenideElement</span> <span class="n">el</span> <span class="o">:</span> <span class="err">$$</span><span class="o">(</span><span class="s">"#selenide-users .user"</span><span class="o">))</span> <span class="o">{</span>
<span class="n">el</span><span class="o">.</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">visible</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>
<p>then it doesn’t compile anymore.</p>
<p>A <strong>fast solution</strong> is to add <code class="language-plaintext highlighter-rouge">asFixedIterable()</code> to <code class="language-plaintext highlighter-rouge">$$</code>:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">for</span> <span class="o">(</span><span class="nc">SelenideElement</span> <span class="n">el</span> <span class="o">:</span> <span class="err">$$</span><span class="o">(</span><span class="s">"#selenide-users .user"</span><span class="o">).</span><span class="na">asFixedIterable</span><span class="o">())</span> <span class="o">{</span>
<span class="n">el</span><span class="o">.</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">visible</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>
<p>But the <strong>right solution</strong> is to rewrite this code and avoid the loop. Most probably, you would better write your
<a href="https://github.com/selenide/selenide/wiki/Custom-collection-conditions">custom collection condition</a>.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2513">PR 2513</a>.</p>
<p>UPD <a href="/2023/10/26/selenide-7.0.1/">From version 7.0.1</a>, it compiles again.</p>
<p><br /></p>
<h3 id="replace-elements-container-by-container">Replaced deprecated class <code class="language-plaintext highlighter-rouge">ElementsContainer</code> by interface <code class="language-plaintext highlighter-rouge">Container</code></h3>
<p>If you extracted parts of your page objects to reusable containers (aka “widgets”), they usually inherited <code class="language-plaintext highlighter-rouge">ElementsContainer</code>:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">WeatherWidget</span> <span class="kd">extends</span> <span class="nc">ElementsContainer</span> <span class="o">{</span>
<span class="nd">@FindBy</span><span class="o">(</span><span class="n">id</span> <span class="o">=</span> <span class="s">"air"</span><span class="o">)</span>
<span class="kd">private</span> <span class="nc">SelenideElement</span> <span class="n">airTemperature</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Now you will need to replace <code class="language-plaintext highlighter-rouge">ElementsContainer</code> by just <code class="language-plaintext highlighter-rouge">Container</code>:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">WeatherWidget</span> <span class="kd">implements</span> <span class="nc">Container</span> <span class="o">{</span>
<span class="nd">@FindBy</span><span class="o">(</span><span class="n">id</span> <span class="o">=</span> <span class="s">"air"</span><span class="o">)</span>
<span class="kd">private</span> <span class="nc">SelenideElement</span> <span class="n">airTemperature</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Interface <code class="language-plaintext highlighter-rouge">Container</code> doesn’t have method <code class="language-plaintext highlighter-rouge">getSelf()</code> anymore. It had been <code class="language-plaintext highlighter-rouge">@Deprecated</code> for a long time.
But if you still need it, we added a better alternative in Selenide 7.0.1: annotation <code class="language-plaintext highlighter-rouge">@Self</code>.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2523">PR 2523</a>.</p>
<p><br /></p>
<h3 id="replace-file-not-found-exception">Replaced <code class="language-plaintext highlighter-rouge">FileNotFoundException</code> by <code class="language-plaintext highlighter-rouge">FileNotDownloadedError</code></h3>
<p>Before today, all methods like <code class="language-plaintext highlighter-rouge">$.download()</code> were declared as <code class="language-plaintext highlighter-rouge">throws FileNotFoundException</code>.
And you had to suffer adding this pointless <code class="language-plaintext highlighter-rouge">throws FileNotFoundException</code> to your tests.
Now you can clean up this trash and remove unnecessary <code class="language-plaintext highlighter-rouge">catch (FileNotFoundException)</code> if you had them.</p>
<p>Now methods like <code class="language-plaintext highlighter-rouge">$.download()</code> will throw <code class="language-plaintext highlighter-rouge">FileNotDownloadedError</code> which is inherited from <code class="language-plaintext highlighter-rouge">AssertionError</code>.
You don’t need to declare nor catch it.
If test could not download the file - test should fail.No additional processing is needed.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2526">PR 2526</a>.</p>
<p><br /></p>
<h3 id="rename-exceptions-to-errors">Renamed <code class="language-plaintext highlighter-rouge">*Exception</code> to <code class="language-plaintext highlighter-rouge">*Error</code></h3>
<p>Personally, I don’t think it matters at all. <br />
But some users didn’t like that some of Selenide classes were named <code class="language-plaintext highlighter-rouge">*Exception</code>, but didn’t extend <code class="language-plaintext highlighter-rouge">java.lang.Exception</code>.</p>
<p>Well, we respect all opinions.
Now Selenide classes inherited from <code class="language-plaintext highlighter-rouge">java.lang.Error</code> are named <code class="language-plaintext highlighter-rouge">*Error</code>.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2485">issue 2485</a> and <a href="https://github.com/selenide/selenide/pull/2530">PR 2530</a>.</p>
<p><br /></p>
<h3 id="remove-deprecated-listener">Removed support for deprecated <code class="language-plaintext highlighter-rouge">WebDriverEventListener</code></h3>
<p>We removed all methods like <code class="language-plaintext highlighter-rouge">addListener()</code> with a parameter of type <code class="language-plaintext highlighter-rouge">org.openqa.selenium.support.events.WebDriverEventListener</code>.</p>
<p>This class has been deprecated in Selenium for a long time.</p>
<p>You should use <code class="language-plaintext highlighter-rouge">addListener()</code> with parameter <code class="language-plaintext highlighter-rouge">org.openqa.selenium.support.events.WebDriverListener</code> instead.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2516">PR 2516</a>.</p>
<p><br /></p>
<h3 id="remove-deprecated-drag-and-drop-methods">Removed deprecated Drag’n’drop methods</h3>
<p>Yet another cleanup. Just replace</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#what"</span><span class="o">).</span><span class="na">dragAndDropTo</span><span class="o">(</span><span class="n">where</span><span class="o">);</span>
</code></pre></div></div>
<p>by</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#what"</span><span class="o">).</span><span class="na">dragAndDrop</span><span class="o">(</span><span class="n">to</span><span class="o">(</span><span class="n">where</span><span class="o">));</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/pull/2519">PR 2519</a>.</p>
<p><br /></p>
<h3 id="remove-deprecated-get-selected-value-methods">Removed deprecated methods <code class="language-plaintext highlighter-rouge">$.getSelectedValue()</code> and <code class="language-plaintext highlighter-rouge">$.getSelectedText()</code></h3>
<p>One more cleanup.</p>
<ol>
<li>Replace <code class="language-plaintext highlighter-rouge">$.getSelectedValue()</code> by <code class="language-plaintext highlighter-rouge">$.getSelectedOptionValue()</code></li>
<li>Replace <code class="language-plaintext highlighter-rouge">$.getSelectedText()</code> by <code class="language-plaintext highlighter-rouge">$.getSelectedOptionText()</code></li>
</ol>
<p>See <a href="https://github.com/selenide/selenide/pull/2521">PR 2521</a>.</p>
<p><br /></p>
<h3 id="remove-deprecated-testng-annotations">Removed deprecated TestNG annotations <code class="language-plaintext highlighter-rouge">@Report</code> and <code class="language-plaintext highlighter-rouge">@GlobalTextReport</code></h3>
<p>These annotations were not needed starting from <a href="https://selenide.org/2022/08/04/selenide-6.7.0/#cancel-report-testng-annotation">Selenide 6.7.0</a>.
Just remove them.
Yes, and delete TestNG, for that matter. ;)</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2517">PR 2517</a>.</p>
<p><br /></p>
<h3 id="remove-other-deprecated-methods">Other cleanup</h3>
<p>Few more cleanups:</p>
<ol>
<li>Replace
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">new</span> <span class="nc">BearerTokenCredentials</span><span class="o">(</span><span class="s">"pwd"</span><span class="o">)</span>
</code></pre></div> </div>
<p>by</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">new</span> <span class="nc">BearerTokenCredentials</span><span class="o">(</span><span class="s">"domain"</span><span class="o">,</span> <span class="s">"pwd"</span><span class="o">)</span>
</code></pre></div> </div>
</li>
<li>Replace
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">.</span><span class="na">should</span><span class="o">(</span><span class="n">appears</span><span class="o">);</span>
</code></pre></div> </div>
<p>by</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">.</span><span class="na">should</span><span class="o">(</span><span class="n">appear</span><span class="o">);</span> <span class="c1">// or just $.shouldBe(visible)</span>
</code></pre></div> </div>
</li>
<li>Replace</li>
</ol>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Selenide</span><span class="o">.</span><span class="na">open</span><span class="o">(</span><span class="n">url</span><span class="o">,</span> <span class="no">BASIC</span><span class="o">,</span> <span class="s">"username"</span><span class="o">,</span> <span class="s">"password"</span><span class="o">);</span>
</code></pre></div></div>
<p>by</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Selenide</span><span class="o">.</span><span class="na">open</span><span class="o">(</span><span class="n">url</span><span class="o">,</span> <span class="no">BASIC</span><span class="o">,</span> <span class="k">new</span> <span class="nc">BasicAuthCredentials</span><span class="o">(</span><span class="s">"username"</span><span class="o">,</span> <span class="s">"password"</span><span class="o">));</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/pull/2518">PR 2518</a>.</p>
<p><br /></p>
<p>Towards progress!</p>
<center>
<img src="/images/2023/10/12-Product-Image.webp" width="300" />
</center>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.19.12023-10-18T00:00:00+00:00https://selenide.org/2023/10/18/selenide-6.19.1
<p>Good morning!</p>
<p>The world is frozen in anticipation, big changes are coming!
Selenide 7.0.0 will be coming soon with an update to Java 11.</p>
<blockquote>
<p>The era of Java8 lambda cuckolds is passing</p>
</blockquote>
<p>At last, we released <strong>the last version</strong> that can run on Java 8:</p>
<p><a href="https://github.com/selenide/selenide/milestone/193?closed=1">Selenide 6.19.1</a></p>
<p>Mostly there are dependency updates, primarily Appium 8.6.0:</p>
<ul>
<li>bump Appium from 8.5.1 to 8.6.0 <a href="https://github.com/selenide/selenide/pull/2494">(#2494)</a></li>
<li>Bump BrowserUpProxy <a href="https://github.com/selenide/selenide/pull/2510">(#2510)</a></li>
<li>Bump Netty from 4.1.98.Final to 4.1.100.Final <a href="https://github.com/selenide/selenide/pull/2484">(#2484)</a> <a href="https://github.com/selenide/selenide/pull/2498">(#2498)</a></li>
<li>Bump LittleProxy from 2.0.21 to 2.0.22 <a href="https://github.com/selenide/selenide/pull/2491">(#2491)</a></li>
<li>Bump Guava from 32.1.2-jre to 32.1.3-jre <a href="https://github.com/selenide/selenide/pull/2499">(#2499)</a></li>
<li>Bump Jackson from 2.15.2 to 2.15.3 <a href="https://github.com/selenide/selenide/pull/2502">(#2502)</a> <a href="https://github.com/selenide/selenide/pull/2503">(#2503)</a></li>
<li>Bump commons-io from 2.13.0 to 2.14.0 <a href="https://github.com/selenide/selenide/pull/2486">(#2486)</a></li>
</ul>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.19.02023-09-28T00:00:00+00:00https://selenide.org/2023/09/28/selenide-6.19.0
<p>Good Sunday! <br />
At the end of September, we released <a href="https://github.com/selenide/selenide/milestone/192?closed=1">Selenide 6.19.0</a>.</p>
<ul class="blogpost-menu">
<li><a href="#add-highlight-method">New method <code class="language-plaintext highlighter-rouge">$.highlight()</code></a></li>
<li><a href="#strip-invisible-spaces-in-collections">Strip invisible spaces in collections</a></li>
<li><a href="#upgrade-to-selenium-4.13.0">Upgrade to Selenium 4.13.0</a></li>
<li><a href="#remove-hub-url-check">Removed strict check for “/wd/hub”</a></li>
<li><a href="#replace-elements-container-by-container">Replaced <code class="language-plaintext highlighter-rouge">ElementsContainer</code> by <code class="language-plaintext highlighter-rouge">Container</code></a></li>
<li><a href="#tap-double-tap">Methods <code class="language-plaintext highlighter-rouge">$.tap()</code>, <code class="language-plaintext highlighter-rouge">$.doubleTap()</code> for mobile apps</a></li>
<li><a href="#add-selector-by-class-and-index">Selector by class+index for mobile apps</a></li>
<li><a href="#news">News</a></li>
</ul>
<p><br /></p>
<h3 id="add-highlight-method">New method <code class="language-plaintext highlighter-rouge">$.highlight()</code> for highlighting a web element</h3>
<p>I feel like we’re opening another Pandora’s box, but what can we do?</p>
<p>Well, we’ve added a method to highlight an element.</p>
<h4 id="what-is-it-needed-for">What is it needed for?</h4>
<p>In normal situations, there is no need. :)</p>
<ul>
<li>When your tests just run automatically on CI, there is no need to watch them. No need to highlight anything.</li>
<li>But when you need to make a cool demo at a conference, or just show running tests to colleagues - here highlighting may be useful.
Or when you are debugging some tricky flaky test where it’s unclear what and when is being clicked.</li>
</ul>
<h4 id="how-exactly-is-it-highlighted">How exactly is it highlighted?</h4>
<p>At the moment, we suggest two highlighting options: with a background (default) or a border.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">HighlightOptions</span><span class="o">.*;</span>
<span class="err">$</span><span class="o">(</span><span class="s">"h1"</span><span class="o">).</span><span class="na">highlight</span><span class="o">();</span> <span class="c1">// by default - background()</span>
<span class="err">$</span><span class="o">(</span><span class="s">"h1"</span><span class="o">).</span><span class="na">highlight</span><span class="o">(</span><span class="n">background</span><span class="o">());</span> <span class="c1">// colored background</span>
<span class="err">$</span><span class="o">(</span><span class="s">"h1"</span><span class="o">).</span><span class="na">highlight</span><span class="o">(</span><span class="n">border</span><span class="o">());</span> <span class="c1">// colored border</span>
</code></pre></div></div>
<p>You can use your own style for background and border:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"h1"</span><span class="o">).</span><span class="na">highlight</span><span class="o">(</span><span class="n">background</span><span class="o">(</span><span class="s">"rgb(85, 180, 250);"</span><span class="o">));</span>
<span class="err">$</span><span class="o">(</span><span class="s">"h1"</span><span class="o">).</span><span class="na">highlight</span><span class="o">(</span><span class="n">border</span><span class="o">(</span><span class="s">"3px solid blue"</span><span class="o">));</span>
</code></pre></div></div>
<p>Or even use totally custom CSS for highlighting:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"h1"</span><span class="o">).</span><span class="na">highlight</span><span class="o">(</span><span class="n">style</span><span class="o">(</span><span class="s">"color: white; background-color: red;"</span><span class="o">));</span>
</code></pre></div></div>
<p><br /></p>
<h4 id="further-development">Further development</h4>
<p>For now, the method only highlights the element you specify.
In the future, it might be worth adding automatic highlighting for each element that is interacted with.
Such highlighting would allow you to make an effective demo or debug a tricky error.</p>
<p>Share your ideas, we’ll think about it.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1277">issue 1277</a>, <a href="https://github.com/selenide/selenide/issues/2395">issue 2395</a> and
<a href="https://github.com/selenide/selenide/pull/2481">PR 2481</a>.</p>
<p><br /></p>
<h3 id="strip-invisible-spaces-in-collections">Strip invisible spaces in collections</h3>
<p>As you remember, in Selenide 6.16.0 we <a href="/2023/07/02/selenide-6.16.0/#speedup-collection-checks">speeded up working with collections</a>
with the help of JavaScript snippets. It turned out that in doing so we slightly changed the behavior for elements containing
invisible spaces and other tricky characters.</p>
<p>Let’s say we have the following element on our page:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><div</span> <span class="na">id=</span><span class="s">"status"</span><span class="nt">></span>
<span class="nt"><span></span> Fighting spirit <span class="nt"></span></span>
<span class="nt"><span></span> seething<span class="ni">&nbsp;</span>\u200Breality <span class="nt"></span></span>
<span class="nt"></div></span>
</code></pre></div></div>
<p>Then a collection check like this:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$$</span><span class="o">(</span><span class="s">"#status span"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">texts</span><span class="o">(</span><span class="s">"Fighting spirit"</span><span class="o">,</span> <span class="s">"seething reality"</span><span class="o">));</span>
</code></pre></div></div>
<p>failed:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Expected</span> <span class="o">:[</span><span class="nc">Fighting</span> <span class="n">spirit</span><span class="o">,</span> <span class="n">seething</span> <span class="n">reality</span><span class="o">]</span>
<span class="nc">Actual</span> <span class="o">:[</span><span class="nc">Fighting</span> <span class="n">spirit</span><span class="o">,</span> <span class="n">seething</span> <span class="n">reality</span><span class="o">]</span>
</code></pre></div></div>
<p>Moreover, the message looks as if the texts are the same.
But in the first line there is a regular space, and in the second there is an invisible space “<code class="language-plaintext highlighter-rouge"></code>”.</p>
<p>Now Selenide will clean up the invisible spaces.
Perhaps it’s arguable whether it’s right or wrong, but it meets WebDriver specification, and Selenium also works like this.
And we will also comply.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2469">issue 2469</a> and <a href="https://github.com/selenide/selenide/pull/2482">PR 2482</a>.<br />
Thanks to <a href="https://github.com/Au6ojlut">Maksim Au6ojlut</a> for <a href="https://github.com/selenide/selenide/issues/2469#issuecomment-1721584046">the hint about spaces</a>.</p>
<p><br /></p>
<h3 id="upgrade-to-selenium-4.13.0">Upgrade to Selenium 4.13.0</h3>
<p>Upgraded Selenium from 4.12.1 to 4.13.0<br />
Here is <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">Selenium changelog</a>.</p>
<p>It contains several important bugfixes, and still runs on Java8. Catch it before he starts requiring Java 11+!</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2479">PR 2479</a>.</p>
<p><br /></p>
<h3 id="remove-hub-url-check">Removed strict check for “/wd/hub”</h3>
<p>If you use Selenoid, you might notice that <code class="language-plaintext highlighter-rouge">selenide-selenoid</code> plugin checked that URL ends with a string <code class="language-plaintext highlighter-rouge">/wd/hub</code>.
It turns out that URL may be different. So we removed this check.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2475">issue 2475</a>.<br />
Thanks <a href="https://github.com/Plodick">Dmitry Plodukhin</a> for <a href="https://github.com/selenide/selenide/pull/2476">PR 2476</a>.</p>
<p><br /></p>
<h3 id="replace-elements-container-by-container">Replaced <code class="language-plaintext highlighter-rouge">ElementsContainer</code> by <code class="language-plaintext highlighter-rouge">Container</code></h3>
<p>In a recent release, we <a href="/2023/09/06/selenide-6.18.0/#no-elements-container-for-page-object">forbid page objects</a> to inherit <code class="language-plaintext highlighter-rouge">ElementsContainer</code>.</p>
<p>This code doesn’t work anymore:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">LoginPage</span> <span class="kd">extends</span> <span class="nc">ElementsContainer</span> <span class="o">{</span>
<span class="o">}</span>
</code></pre></div></div>
<p>I still insist that a page object doesn’t really need to extend <code class="language-plaintext highlighter-rouge">ElementsContainer</code>. But few users complained that they
cannot rewrite their code because of legacy etc.<br />
For such project, we created interface <code class="language-plaintext highlighter-rouge">Container</code>:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">LoginPage</span> <span class="kd">implements</span> <span class="nc">Container</span> <span class="o">{</span>
<span class="o">}</span>
</code></pre></div></div>
<p>For the usual widgets, we also recommend changing <code class="language-plaintext highlighter-rouge">extends ElementsContainer</code> to <code class="language-plaintext highlighter-rouge">implements Container</code>.</p>
<p>The only difference is that it’s interface, not an abstract class (you need to write “implements” instead of “extends”),
and it doesn’t have method <code class="language-plaintext highlighter-rouge">getSelf()</code>. And you shouldn’t really need it.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2439">issue 2439</a> and <a href="https://github.com/selenide/selenide/pull/2465">PR 2465</a>.</p>
<p><br /></p>
<h3 id="tap-double-tap">Methods <code class="language-plaintext highlighter-rouge">$.tap()</code>, <code class="language-plaintext highlighter-rouge">$.doubleTap()</code> for mobile apps</h3>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">SelenideAppium</span><span class="o">.</span><span class="err">$</span><span class="o">;</span>
<span class="err">$</span><span class="o">(</span><span class="nc">By</span><span class="o">.</span><span class="na">name</span><span class="o">(</span><span class="s">"ComputeSumButton"</span><span class="o">)).</span><span class="na">tap</span><span class="o">();</span>
<span class="err">$</span><span class="o">(</span><span class="nc">AppiumBy</span><span class="o">.</span><span class="na">xpath</span><span class="o">(</span><span class="s">"//android.widget.Button"</span><span class="o">)).</span><span class="na">doubleTap</span><span class="o">();</span>
<span class="err">$</span><span class="o">(</span><span class="nc">AppiumBy</span><span class="o">.</span><span class="na">xpath</span><span class="o">(</span><span class="s">".//*[@text='People Names']"</span><span class="o">)).</span><span class="na">tap</span><span class="o">(</span><span class="n">longPressFor</span><span class="o">(</span><span class="n">ofSeconds</span><span class="o">(</span><span class="mi">4</span><span class="o">)));</span>
</code></pre></div></div>
<p>Thanks <a href="https://github.com/qwez">qwez</a> for <a href="https://github.com/selenide/selenide/pull/2467">PR 2467</a>.</p>
<p><br /></p>
<h3 id="add-selector-by-class-and-index">Selector by class+index for mobile apps</h3>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">AppiumSelectors</span><span class="o">.</span><span class="na">byClassNameAndIndex</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">SelenideAppium</span><span class="o">.</span><span class="err">$</span><span class="o">;</span>
<span class="err">$</span><span class="o">(</span><span class="n">byClassNameAndIndex</span><span class="o">(</span><span class="s">"android.widget.TextView"</span><span class="o">,</span> <span class="mi">7</span><span class="o">)).</span><span class="na">tap</span><span class="o">();</span>
</code></pre></div></div>
<p>Thanks to <a href="https://github.com/amuthansakthivel">Amuthan Sakthivel</a> for <a href="https://github.com/selenide/selenide/pull/2440">PR 2440</a>.</p>
<p><br /></p>
<h3 id="news">News</h3>
<ul>
<li><a href="https://github.com/titusfortner/selenium-logger">Selenium logger</a> - a new project from Titus Fortner</li>
<li><a href="https://www.baeldung.com/selenide">Introduction to Selenide</a> - The historical moment! A post about Selenide on the legendary resource Baeldung.</li>
<li><a href="https://www.youtube.com/watch?v=C8rbEuvvg0I&ab_channel=LambdaTest">Selenide appium</a> - A video about Selenide from the last LambdaTest conference by Amuthan Sakthivel</li>
<li><a href="https://intexsoft.com/blog/selenide-test-automation-using-selenoid-in-the-docker-container/">Selenide test automation: using Selenoid in docker</a> by Dora & Margarita</li>
<li><a href="https://zenn.dev/ragnar1904/articles/selenide-essentials">Things to keep in mind when using Selenide</a> - post about Selenide in Japanese by nilwurtz</li>
<li><a href="https://updates4devs.com/intro-to-selenidebaeldung/?feed_id=28562">Intro to Selenide</a> By Updates4Devs.com</li>
</ul>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.18.02023-09-06T00:00:00+00:00https://selenide.org/2023/09/06/selenide-6.18.0
<p>Good night!</p>
<p>Good news.<br />
We released <a href="https://github.com/selenide/selenide/milestone/190?closed=1">Selenide 6.18.0</a>.</p>
<ul class="blogpost-menu">
<li><a href="#show-actual-texts-in-collections">Show actual texts in collections</a></li>
<li><a href="#update-to-selenium-4.12.1">Upgrade to Selenium 4.12.1</a></li>
<li><a href="#restore-basic-auth-via-cdp">Restore BasicAuth via DevTools</a></li>
<li><a href="#add-method-get-options">Added method <code class="language-plaintext highlighter-rouge">$$.getOptions()</code></a></li>
<li><a href="#get-focused-element-lazy-loaded">Method <code class="language-plaintext highlighter-rouge">getFocusedElement()</code> made lazy</a></li>
<li><a href="#support-appium-elements-in-page-objects">Fields <code class="language-plaintext highlighter-rouge">SelenideAppiumElement</code> in page objects</a></li>
<li><a href="#exact-scroll-in-appium">Precise scrolling in mobile apps</a></li>
<li><a href="#no-elements-container-for-page-object">Don’t inherit page objects from <code class="language-plaintext highlighter-rouge">ElementsContainer</code></a></li>
<li><a href="#update-dependencies">Updated dependencies</a></li>
<li><a href="#statistics">Statistics</a></li>
</ul>
<p><br /></p>
<h3 id="show-actual-texts-in-collections">Show actual texts in collections</h3>
<p>In Selenide 6.16.0, we <a href="/2023/07/02/selenide-6.16.0/#speedup-collection-checks">speed up collections checks</a>.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$$</span><span class="o">(</span><span class="s">".troubles"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">texts</span><span class="o">(</span>
<span class="s">"Health"</span><span class="o">,</span> <span class="s">"Emptiness"</span><span class="o">,</span>
<span class="s">"Financial Crisis"</span><span class="o">,</span> <span class="s">"Career Pressure"</span><span class="o">));</span>
</code></pre></div></div>
<p>One of the optimizations was: if collection size doesn’t match the number of expected texts, Selenide doesn’t even start loading texts of elements,
but immediately throws an error:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">List</span> <span class="n">size</span> <span class="nl">mismatch:</span> <span class="nl">expected:</span> <span class="o">=</span> <span class="mi">4</span><span class="o">,</span> <span class="nl">actual:</span> <span class="mi">3</span>
</code></pre></div></div>
<p>But people started complaining that they want to see the actual text even in this case.<br />
This seems to be a case where convenience is more important than speed. And your tests don’t fail too often, right? ;)</p>
<p>That’s why we will show both sizes and texts from this release:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">List</span> <span class="n">size</span> <span class="nf">mismatch</span> <span class="o">(</span><span class="nl">expected:</span> <span class="mi">4</span><span class="o">,</span> <span class="nl">actual:</span> <span class="mi">3</span><span class="o">)</span>
<span class="nc">Actual</span> <span class="o">(</span><span class="mi">3</span><span class="o">):</span> <span class="o">[</span><span class="nc">Health</span><span class="o">,</span> <span class="nc">Emptiness</span><span class="o">,</span> <span class="nc">Financial</span> <span class="nc">Crisis</span><span class="o">]</span>
<span class="nf">Expected</span> <span class="o">(</span><span class="mi">4</span><span class="o">):</span> <span class="o">[</span><span class="nc">Health</span><span class="o">,</span> <span class="nc">Emptiness</span><span class="o">,</span> <span class="nc">Financial</span> <span class="nc">Crisis</span><span class="o">,</span> <span class="nc">Career</span> <span class="nc">Pressure</span><span class="o">]</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/2434">issue 2434</a> and <a href="https://github.com/selenide/selenide/pull/2456">PR 2456</a>.</p>
<p><br /></p>
<h3 id="update-to-selenium-4.12.1">Updated Selenium from 4.11.0 to 4.12.1</h3>
<p>Changelog is <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">here</a>.
Among others, it fixes that <a href="https://github.com/SeleniumHQ/selenium/issues/12576">deadlock in devtools</a>, because of which we had to make the previous release.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2452">PR 2452</a>.</p>
<p><br /></p>
<h3 id="restore-basic-auth-via-cdp">Restore BasicAuth via DevTools</h3>
<p>In Selenide 6.16.0, we implemented <a href="/2023/07/02/selenide-6.16.0/#improve-basic-auth-in-chromium-browsers">BasicAuth authentication via <code class="language-plaintext highlighter-rouge">HasAuthentication</code> mechanism</a> (in Chromium-based browsers).</p>
<p>Later we had to roll it back due to the aforementioned deadlock in webdriver.<br />
Now Selenium has been updated, the deadlock has been fixed, and we have returned the authorization back.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2336">issue 2336</a>, <a href="https://github.com/selenide/selenide/pull/2358">PR 2358</a> and <a href="https://github.com/selenide/selenide/pull/2452">PR 2452</a>.</p>
<p><br /></p>
<h3 id="add-method-get-options">Added method <code class="language-plaintext highlighter-rouge">$$.getOptions()</code></h3>
<p>Selenide has method <code class="language-plaintext highlighter-rouge">$$.getSelectedOptions()</code> which returns <em>selected</em> options of a <code class="language-plaintext highlighter-rouge"><select></code> element.<br />
Now we added a similar method <code class="language-plaintext highlighter-rouge">$$.getOptions()</code>, which returns <em>all</em> options.</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#hero"</span><span class="o">).</span><span class="na">getOptions</span><span class="o">()</span>
<span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">texts</span><span class="o">(</span><span class="s">"Frodo"</span><span class="o">,</span> <span class="s">"Samwise"</span><span class="o">,</span> <span class="s">"Peregrin"</span><span class="o">,</span> <span class="s">"Meriadoc"</span><span class="o">));</span>
<span class="err">$</span><span class="o">(</span><span class="s">"select#hero"</span><span class="o">).</span><span class="na">selectOption</span><span class="o">(</span><span class="s">"Samwise"</span><span class="o">);</span>
<span class="err">$</span><span class="o">(</span><span class="s">"select#hero"</span><span class="o">).</span><span class="na">getSelectedOptions</span><span class="o">()</span>
<span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">texts</span><span class="o">(</span><span class="s">"Samwise"</span><span class="o">));</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/2445">issue 2445</a> and <a href="https://github.com/selenide/selenide/pull/2446">PR 2446</a>.</p>
<p><br /></p>
<h3 id="get-focused-element-lazy-loaded">Method <code class="language-plaintext highlighter-rouge">getFocusedElement()</code> made lazy</h3>
<p>Now method <code class="language-plaintext highlighter-rouge">Selenide.getFocusedElement()</code> returns <code class="language-plaintext highlighter-rouge">SelenideElement</code> instead of <code class="language-plaintext highlighter-rouge">WebElement</code>.</p>
<p>It effectively means lazy initialization, re-tries, “should*” checks etc.:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">getFocusedElement</span><span class="o">()</span>
<span class="o">.</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">tagName</span><span class="o">(</span><span class="s">"input"</span><span class="o">),</span> <span class="n">id</span><span class="o">(</span><span class="s">"otpCode"</span><span class="o">));</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/pull/2454">PR 2454</a>.</p>
<p><br /></p>
<h3 id="support-appium-elements-in-page-objects">Added support for <code class="language-plaintext highlighter-rouge">SelenideAppiumElement</code> fields in page objects</h3>
<p>If you write tests for mobile apps using our plugin <code class="language-plaintext highlighter-rouge">selenide-appium</code>, now you can declare fields in your page objects with type
<code class="language-plaintext highlighter-rouge">SelenideAppiumElement</code> instead of <code class="language-plaintext highlighter-rouge">SelenideElement</code>.</p>
<p>It gives you some additional mobile-specific methods like <code class="language-plaintext highlighter-rouge">hideKeyboard()</code>, <code class="language-plaintext highlighter-rouge">swipe()</code> etc.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">LoginPage</span> <span class="o">{</span>
<span class="nd">@AndroidFindBy</span><span class="o">(</span><span class="n">accessibility</span> <span class="o">=</span> <span class="s">"Username input field"</span><span class="o">)</span>
<span class="nc">SelenideAppiumElement</span> <span class="n">login</span><span class="o">;</span>
<span class="nd">@AndroidFindBy</span><span class="o">(</span><span class="n">accessibility</span> <span class="o">=</span> <span class="s">"Password input field"</span><span class="o">)</span>
<span class="nc">SelenideElement</span> <span class="n">password</span><span class="o">;</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">login</span><span class="o">()</span> <span class="o">{</span>
<span class="n">password</span><span class="o">.</span><span class="na">swipeTo</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/2437">issue 2437</a> and <a href="https://github.com/selenide/selenide/pull/2438">PR 2438</a>.</p>
<p><br /></p>
<h3 id="exact-scroll-in-appium">Precise scrolling in mobile apps</h3>
<p>Continuing the theme of mobile phones.
In plugin <code class="language-plaintext highlighter-rouge">selenide-appium</code>, there is method <code class="language-plaintext highlighter-rouge">scroll</code>:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">AppiumScrollOptions</span><span class="o">.</span><span class="na">with</span><span class="o">;</span>
<span class="err">$</span><span class="o">.</span><span class="na">scroll</span><span class="o">(</span><span class="n">with</span><span class="o">(</span><span class="no">UP</span><span class="o">,</span> <span class="mi">20</span><span class="o">));</span> <span class="c1">// swipe up, no more than 20 times</span>
</code></pre></div></div>
<p>Now you can specify the starting and ending position for the swipe (percentage of screen height):</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">AppiumScrollOptions</span><span class="o">.</span><span class="na">up</span><span class="o">;</span>
<span class="err">$</span><span class="o">.</span><span class="na">scroll</span><span class="o">(</span><span class="n">up</span><span class="o">(</span><span class="mi">10</span><span class="o">,</span> <span class="mi">80</span><span class="o">));</span> <span class="c1">// swipe from 10% point to 80% point</span>
</code></pre></div></div>
<p>Thanks to <a href="https://github.com/qwez">qwez</a> for <a href="https://github.com/selenide/selenide/pull/2449">PR 2449</a>.</p>
<p><br /></p>
<h3 id="no-elements-container-for-page-object">Don’t inherit page objects from <code class="language-plaintext highlighter-rouge">ElementsContainer</code></h3>
<p>Some users complained about this warning from Selenide:</p>
<blockquote>
<p>WARN com.codeborne.selenide.impl.SelenidePageFactory - Cannot initialize field private com.codeborne.selenide.SelenideElement com.codeborne.selenide.ElementsContainer.self</p>
</blockquote>
<p>We realized it happens when you inherit a page object from <code class="language-plaintext highlighter-rouge">ElementsContainer</code>:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">LoginPage</span> <span class="kd">extends</span> <span class="nc">ElementsContainer</span> <span class="o">{</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Which is <strong>not really needed</strong>. In fact, you cannot do it anymore. :)</p>
<p>Initially, <code class="language-plaintext highlighter-rouge">ElementsContainer</code> was intended to declare components <em>inside</em> page objects:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">LoginPage</span> <span class="o">{</span>
<span class="nd">@FindBy</span><span class="o">(</span><span class="n">id</span><span class="o">=</span><span class="s">"weather"</span><span class="o">)</span>
<span class="nc">WeatherWidget</span> <span class="n">weatherWidget</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">class</span> <span class="nc">WeatherWidget</span> <span class="kd">extends</span> <span class="nc">ElementsContainer</span> <span class="o">{</span>
<span class="nd">@FindBy</span><span class="o">(</span><span class="n">id</span><span class="o">=</span><span class="s">"temperature"</span><span class="o">)</span>
<span class="nc">SelenideElement</span> <span class="n">temperature</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Just remove <code class="language-plaintext highlighter-rouge">extends ElementsContainer</code> from your page objects, and everything just works.</p>
<p>P.S. The point is, that these objects have different lifecycle:</p>
<ol>
<li>Page objects can be created using method <code class="language-plaintext highlighter-rouge">page</code>: like, <code class="language-plaintext highlighter-rouge">LoginPage page = Selenide.page();</code>. And method <code class="language-plaintext highlighter-rouge">page</code> <em>does NOT require</em> your class to <code class="language-plaintext highlighter-rouge">extend ElementsContainer</code>.</li>
<li>And some fields of your page object can <code class="language-plaintext highlighter-rouge">extend ElementsContainer</code>. It makes Selenide search <code class="language-plaintext highlighter-rouge">@FindBy</code> elements inside of these classes.</li>
</ol>
<p>See <a href="https://github.com/selenide/selenide/issues/2439">issue 2439</a> and <a href="https://github.com/selenide/selenide/pull/2455">PR 2455</a>.</p>
<p><br /></p>
<h3 id="update-dependencies">Updated dependencies</h3>
<ul>
<li>bump LittleProxy from 2.0.19 to 2.0.20 (fixes a memory leak in Selenide proxy)</li>
<li>update vulnerable jackson dependency - see <a href="https://github.com/selenide/selenide/pull/2442">PR 2442</a></li>
</ul>
<p><br /></p>
<h3 id="statistics">Statistics</h3>
<p>The number of monthly downloads of Selenide has exceeded 670 thousands!</p>
<center>
<img src="/images/2023/09/selenide.downloads.png" width="800" />
</center>
<p><br />
It’s getting serious…</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.17.22023-08-24T00:00:00+00:00https://selenide.org/2023/08/24/selenide-6.17.2
<p>Good evening!</p>
<p>Today is August, 24 - Ukraine Independence Day. <br />
And in honor of this holiday - a small release <a href="https://github.com/selenide/selenide/milestone/189?closed=1">Selenide 6.17.2</a>.</p>
<p><br /></p>
<h3 id="un-hanged-the-hanging-webdriver-again">Un-hanged the hanging webdriver. Again.</h3>
<p><a href="/2023/08/20/selenide-6.17.1/">In the previous release</a>, we fixed the problem with hanging webdriver <em>for most users</em>.<br />
But the unfortunate ones remained, who are forced to open the tested sites in Chrome through BasicAuth.
For these users, webdriver still hangs.</p>
<p>What was left for us? We had to revert <a href="https://github.com/selenide/selenide/pull/2358">CDP-based authentication</a> until the
<a href="https://github.com/SeleniumHQ/selenium/issues/12576">webdriver issue</a> gets fixed.</p>
<h3 id="how-to-reproduce-the-problem">How to reproduce the problem</h3>
<p>If you want to reproeuce the problem, run this test:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">public</span> <span class="kd">class</span> <span class="nc">BasicAuthTest</span> <span class="o">{</span>
<span class="nd">@RepeatedTest</span><span class="o">(</span><span class="mi">2</span><span class="o">)</span>
<span class="kt">void</span> <span class="nf">this_snippet_hangs_during_second_run</span><span class="o">()</span> <span class="o">{</span>
<span class="n">open</span><span class="o">(</span><span class="s">"https://the-internet.herokuapp.com/basic_auth"</span><span class="o">,</span> <span class="no">BASIC</span><span class="o">,</span>
<span class="k">new</span> <span class="nf">BasicAuthCredentials</span><span class="o">(</span><span class="s">"the-internet.herokuapp.com"</span><span class="o">,</span> <span class="s">"admin"</span><span class="o">,</span> <span class="s">"admin"</span><span class="o">));</span>
<span class="err">$</span><span class="o">(</span><span class="s">"#content"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Congratulations!"</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>The first run works, the second run hangs. On Selenide 6.17.1.</p>
<p>And on Selenide 6.17.2 it doesn’t freeze anymore. Hooray.</p>
<p><br /></p>
<center>
<img src="/images/2023/08/happy-independence-day-ukraine-vector-21712783.jpg" width="300" />
</center>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.17.12023-08-20T00:00:00+00:00https://selenide.org/2023/08/20/selenide-6.17.1
<p>Good morning!
Today is August, 20 - <a href="https://www.visitestonia.com/en/why-estonia/estonia-celebrates-regained-independence">Restoration of Independence day</a> in Estonia.</p>
<p>In honor of this holiday - a small release <a href="https://github.com/selenide/selenide/milestone/188?closed=1">Selenide 6.17.1</a>!</p>
<ul>
<li><a href="#fix-hanging-webdriver">Un-hang hanging webdriver</a></li>
<li><a href="#support-type-in-mobile-apps">Added support for <code class="language-plaintext highlighter-rouge">$.type()</code> in mobile apps</a></li>
<li><a href="#fix-type-with-keys">Fixed method <code class="language-plaintext highlighter-rouge">$.type(Keys.*)</code></a></li>
<li><a href="#remove-spaces-from-texts">Removed spaces from <code class="language-plaintext highlighter-rouge">$$.texts()</code></a>
<p><br /></p>
</li>
</ul>
<h3 id="fix-hanging-webdriver">Un-hang hanging webdriver</h3>
<p>In Selenide 6.16.0 (<a href="https://github.com/selenide/selenide/pull/2358">PR 2358</a>), we occasionally introduced a bug that
caused webdriver hanging in some situations.
More exactly, if you call <code class="language-plaintext highlighter-rouge">open(url, pageClass)</code> twice, then webdriver hangs forever.</p>
<p>Wow. :)</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">this_snippet_hangs</span><span class="o">()</span> <span class="o">{</span>
<span class="nc">Selenide</span><span class="o">.</span><span class="na">open</span><span class="o">(</span><span class="s">"https://www.google.com/"</span><span class="o">,</span> <span class="nc">GooglePage</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="nc">Selenide</span><span class="o">.</span><span class="na">open</span><span class="o">(</span><span class="s">"https://www.google.com/"</span><span class="o">,</span> <span class="nc">GooglePage</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>
<p>In fact, I found that this is <a href="https://github.com/SeleniumHQ/selenium/issues/12576">a bug in webdriver</a>,
because it’s <a href="https://github.com/asolntsev/selenium-deadlock">reproducible</a> with pure Selenium.
And changes in Selenide 6.16.0 just made it <em>easily reproducible</em>.</p>
<p>Now we fixed this problem for most users (but not for all).<br />
We will wait for the full fix on webdriver side.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2424">issue 2424</a> and <a href="https://github.com/selenide/selenide/pull/2428">PR 2428</a>.</p>
<blockquote>
<p>Huge thans for <a href="https://github.com/extryd">extryd</a> for a concise problem description with steps to reproduce.
Such a description is an invaluable help to maintainers. I wish all tickets were like this!</p>
</blockquote>
<p><br /></p>
<h3 id="support-type-in-mobile-apps">Added support for <code class="language-plaintext highlighter-rouge">$.type()</code> in mobile apps</h3>
<p>In a previous release, we added method <code class="language-plaintext highlighter-rouge">type</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="na">type</span><span class="o">(</span><span class="s">"Type me slowly with delays"</span><span class="o">);</span>
</code></pre></div></div>
<p>that types the text slowly, with delays. Useful for testing autocompletion, search etc.</p>
<p>But it turned out that it didn’t work in mobile apps (<a href="https://github.com/selenide/selenide/tree/main/modules/appium">selenide-appium</a>). Now it will work.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2191#issuecomment-1667578383">issue</a> and <a href="https://github.com/selenide/selenide/pull/2408">PR 2408</a>.</p>
<p><br /></p>
<h3 id="fix-type-with-keys">Fixed method <code class="language-plaintext highlighter-rouge">$.type(Keys.*)</code></h3>
<p>The abovementioned method <code class="language-plaintext highlighter-rouge">type</code> method accepts not only strings, but also <code class="language-plaintext highlighter-rouge">CharSequence</code>.
Which means this code should also work:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kn">import</span> <span class="nn">org.openqa.selenium.Keys</span><span class="o">;</span>
<span class="err">$</span><span class="o">(</span><span class="s">"input"</span><span class="o">).</span><span class="na">type</span><span class="o">(</span><span class="nc">Keys</span><span class="o">.</span><span class="na">ENTER</span><span class="o">);</span>
</code></pre></div></div>
<p>But it was broken because tried to case <code class="language-plaintext highlighter-rouge">Keys.ENTER</code> (which is <code class="language-plaintext highlighter-rouge">CharSequence</code>) to type <code class="language-plaintext highlighter-rouge">String</code>.
Now it works (though it’s still not clear why it might be useful).</p>
<p>Thanks to <a href="https://github.com/bereg2k">Oleg Berezhnoy</a> for observation and <a href="https://github.com/selenide/selenide/issues/2422">issue 2422</a>.<br />
Fixed in <a href="https://github.com/selenide/selenide/pull/2421">PR 2421</a>.</p>
<p><br /></p>
<h3 id="remove-spaces-from-texts">Removed leading/trailing spaces from <code class="language-plaintext highlighter-rouge">$$.texts()</code></h3>
<p>In Selenide 6.16.0, we <a href="/2023/07/02/selenide-6.16.0/#speedup-collection-checks">accelerated work with collections</a> with a help of JavaScript code. <br />
But abovementioned <a href="https://github.com/bereg2k">Oleg Berezhnoy</a> revealed that we occasionally changes the behaviour of method
<code class="language-plaintext highlighter-rouge">$$.texts()</code>. Before, it returned texts of elements without leading and trailing spaces:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">assertThat</span><span class="o">(</span><span class="err">$$</span><span class="o">(</span><span class="s">".burnees"</span><span class="o">).</span><span class="na">texts</span><span class="o">()).</span><span class="na">isEqualTo</span><span class="o">(</span><span class="nc">List</span><span class="o">.</span><span class="na">of</span><span class="o">(</span>
<span class="s">"SIG"</span><span class="o">,</span>
<span class="s">"Olenegorsky Gornyak"</span><span class="o">,</span>
<span class="s">"Air base Soltsy"</span><span class="o">,</span>
<span class="s">"Chongar bridges"</span><span class="o">,</span>
<span class="s">"Henichesk Bridge"</span>
<span class="o">));</span>
</code></pre></div></div>
<p>And starting from 6.16.0, it returned texts with leading/trailing spaces:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">assertThat</span><span class="o">(</span><span class="err">$$</span><span class="o">(</span><span class="s">".burnees"</span><span class="o">).</span><span class="na">texts</span><span class="o">()).</span><span class="na">isEqualTo</span><span class="o">(</span><span class="nc">List</span><span class="o">.</span><span class="na">of</span><span class="o">(</span>
<span class="s">" SIG "</span><span class="o">,</span>
<span class="s">" Olenegorsky Gornyak "</span><span class="o">,</span>
<span class="s">" Air base Soltsy "</span><span class="o">,</span>
<span class="s">" Chongar bridges "</span><span class="o">,</span>
<span class="s">" Henichesk Bridge "</span>
<span class="o">));</span>
</code></pre></div></div>
<p>This is perhaps a disputable which one is correct, but this is how the standard <code class="language-plaintext highlighter-rouge">WebElement.getText()</code> method works.
So we didn’t argue. Now <code class="language-plaintext highlighter-rouge">$$.texts()</code> trims head and tail spaces again.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2419">issue 2419</a> and <a href="https://github.com/selenide/selenide/pull/2427">PR 2427</a>.</p>
<p><br /></p>
<center>
<img src="/images/2023/08/restoration-independence-taasiseseisvumispaev-estonia.png" width="300" />
</center>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.17.02023-08-02T00:00:00+00:00https://selenide.org/2023/08/02/selenide-6.17.0
<p>Good morning!</p>
<p>Don’t wait to upgrade to <a href="https://github.com/selenide/selenide/milestone/187?closed=1">Selenide 6.17.0</a>!</p>
<ul>
<li><a href="#update-to-selenium-4.11.0">Upgraded to Selenium 4.11.0</a></li>
<li><a href="#replace-webdrivermanager-by-selenium-manager">Replaced WebDriverManager by SeleniumManager</a></li>
<li><a href="#support-java8-again">Restored support for Java 8</a></li>
<li><a href="#add-method-type">Added method <code class="language-plaintext highlighter-rouge">$.type()</code> for slow typing</a></li>
<li><a href="#click-with-long-press">For mobile apps: click with long press</a></li>
<li><a href="#swipe-right-and-left">For mobile apps: swipe left and right</a></li>
<li><a href="#statistics">Statistics</a>
<p><br /></p>
</li>
</ul>
<h3 id="update-to-selenium-4.11.0">Upgraded to Selenium 4.11.0</h3>
<p>We upgraded Selenium version from 4.10.0 to 4.11.0.</p>
<p>Read the full Selenium changelog <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">here</a>.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2393">PR 2393</a>.</p>
<p><br /></p>
<h3 id="replace-webdrivermanager-by-selenium-manager">Replaced WebDriverManager by SeleniumManager</h3>
<p>Starting from version 4.6.0, Selenium has built-in tool for downloading webdriver binaries - SeleniumManager.
Afaik, it’s developed by the same <a href="https://bonigarcia.dev/">Boni Garcia</a>, who created WebDriverManager.
But now it’s an official part of Selenium project.</p>
<p>Read more about SeleniumManager <a href="https://www.selenium.dev/blog/2023/whats-new-in-selenium-manager-with-selenium-4.11.0/">here</a>.</p>
<p><strong>And now Selenide uses SeleniumManager instead of WebDriverManager.</strong></p>
<ul>
<li>Yes, we had to remove setting <code class="language-plaintext highlighter-rouge">Configuration.driverManagerEnabled</code> and method <code class="language-plaintext highlighter-rouge">DriverFactory.setupWebdriverBinary</code>.
It might cause compilation errors in your projects.</li>
<li>Yes, it’s slightly bad that we did it <em>unexpectedly</em>. Usually we don’t remove the API immediately, but first mark it as
<code class="language-plaintext highlighter-rouge">@Deprecated</code>, and remove only in next major release.</li>
</ul>
<p>But we had no choice.</p>
<p>Starting from version 5.4.0, WDM started requiring Java11+ and stopped working with Chrome 115.
While SeleniumManager still works on Java 8 and supports Chrome 115. And works out of the box. <em>What else was left for us?</em></p>
<p>See <a href="https://github.com/selenide/selenide/issues/2402">issue 2402</a> and <a href="https://github.com/selenide/selenide/pull/2400">PR 2400</a>.</p>
<p><br /></p>
<p>P.S. If you still want to use WebDriverManager - not a problem. Just add it explicitly as a dependency to your project
and call in the beginning of your tests:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">WebDriverManager</span><span class="o">.</span><span class="na">chromedriver</span><span class="o">().</span><span class="na">setup</span><span class="o">();</span>
<span class="nc">WebDriverManager</span><span class="o">.</span><span class="na">firefoxdriver</span><span class="o">().</span><span class="na">setup</span><span class="o">();</span>
<span class="nc">WebDriverManager</span><span class="o">.</span><span class="na">edgedriver</span><span class="o">().</span><span class="na">setup</span><span class="o">();</span>
<span class="n">etc</span><span class="o">.</span>
</code></pre></div></div>
<p><br /></p>
<h3 id="support-java8-again">Restored support for Java 8</h3>
<p>In the last release, Selenide occasionally started requiring Java 11. It happened because of WebDriverManager update
mentioned before.</p>
<p>Now it’s gone: no WebDriverManager - no problems. :)</p>
<p>Oldschoolers, you can run your tests on Java 8 again.</p>
<blockquote>
<p>Nevertheless, I recommend you to upgrade to Java 11<br />
(or even better to Java 17).<br />
In the following autumn, Selenium will upgrade to Java 11 anyway, and then you will definitely have no choice.</p>
</blockquote>
<p>See <a href="https://github.com/selenide/selenide/issues/2385">issue 2385</a> and <a href="https://github.com/selenide/selenide/pull/2400">PR 2400</a>.</p>
<p><br /></p>
<h3 id="add-method-type">Added method <code class="language-plaintext highlighter-rouge">$.type()</code> for slow typing</h3>
<p>This feature has been requested for a very long time. And finally!</p>
<p>Method <code class="language-plaintext highlighter-rouge">$.type()</code> does almost the same as <code class="language-plaintext highlighter-rouge">$.sendKeys()</code>, but slowly. With delays between key presses. It emulates like
a real user is typing a text. May be useful for testing autocompletion, automated suggestions, hints, validation etc.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">TypeOptions</span><span class="o">.*;</span>
<span class="err">$</span><span class="o">(</span><span class="s">"#query"</span><span class="o">).</span><span class="na">type</span><span class="o">(</span><span class="s">"Who the fuck is yevgeny prigozhin"</span><span class="o">);</span>
<span class="err">$</span><span class="o">(</span><span class="s">"#query"</span><span class="o">).</span><span class="na">type</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Who the fuck is dmitry utkin"</span><span class="o">));</span>
<span class="err">$</span><span class="o">(</span><span class="s">"#query"</span><span class="o">).</span><span class="na">type</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Who the fuck is lvova-belova"</span><span class="o">).</span><span class="na">withDelay</span><span class="o">(</span><span class="n">ofMillis</span><span class="o">(</span><span class="mi">100</span><span class="o">)));</span>
</code></pre></div></div>
<p>By default, the delay between key presses is 200 milliseconds.</p>
<p>Thanks to <a href="https://github.com/amuthansakthivel">Amuthan Sakthivel</a> for <a href="https://github.com/selenide/selenide/pull/2191">PR 2191</a>.</p>
<p><br /></p>
<h3 id="click-with-long-press">For mobile apps: click with long press</h3>
<p>Now you can use this gesture when testing mobile apps:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">SelenideAppium</span><span class="o">.</span><span class="err">$</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">AppiumClickOptions</span><span class="o">.*;</span>
<span class="err">$</span><span class="o">.</span><span class="na">click</span><span class="o">(</span><span class="n">longPress</span><span class="o">());</span> <span class="c1">// by default 3 seconds</span>
<span class="err">$</span><span class="o">.</span><span class="na">click</span><span class="o">(</span><span class="n">longPressFor</span><span class="o">(</span><span class="nc">Duration</span><span class="o">.</span><span class="na">ofSeconds</span><span class="o">(</span><span class="mi">4</span><span class="o">)));</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/2370">issue 2370</a>.
Thanks to <a href="https://github.com/amuthansakthivel">Amuthan Sakthivel</a> for <a href="https://github.com/selenide/selenide/pull/2381">PR 2381</a>.</p>
<p><br /></p>
<h3 id="swipe-right-and-left">For mobile apps: swipe left and right</h3>
<p>Now you can use this gesture when testing mobile apps:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">SelenideAppium</span><span class="o">.</span><span class="err">$</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">appium</span><span class="o">.</span><span class="na">AppiumSwipeOptions</span><span class="o">.*;</span>
<span class="err">$</span><span class="o">.</span><span class="na">swipeTo</span><span class="o">();</span> <span class="c1">// by default swipes to the right</span>
<span class="err">$</span><span class="o">.</span><span class="na">swipe</span><span class="o">(</span><span class="n">right</span><span class="o">());</span>
<span class="err">$</span><span class="o">.</span><span class="na">swipe</span><span class="o">(</span><span class="n">right</span><span class="o">(</span><span class="mi">20</span><span class="o">));</span>
<span class="err">$</span><span class="o">.</span><span class="na">swipe</span><span class="o">(</span><span class="n">left</span><span class="o">());</span>
<span class="err">$</span><span class="o">.</span><span class="na">swipe</span><span class="o">(</span><span class="n">left</span><span class="o">(</span><span class="mi">30</span><span class="o">));</span>
</code></pre></div></div>
<p>Thanks to <a href="https://github.com/amuthansakthivel">Amuthan Sakthivel</a> for <a href="https://github.com/selenide/selenide/pull/2369">PR 2369</a>.</p>
<p><br /></p>
<p>So, update, try and share:</p>
<blockquote>
<p>How do you like SeleniumManager?<br />
Everything is broken, or we can live with it?</p>
</blockquote>
<p><br /></p>
<h3 id="statistics">Statistics</h3>
<p>Monthly downloads count of selenide.jar exceeded 649 thousands!</p>
<center>
<img src="/images/2023/07/selenide.downloads.png" width="800" />
</center>
<p>(The previous record was in March: 602 thousand)</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.16.12023-07-24T00:00:00+00:00https://selenide.org/2023/07/24/selenide-6.16.1
<p>Hello, people!</p>
<p>We released a small update <a href="https://github.com/selenide/selenide/milestone/186?closed=1">Selenide 6.16.1</a>.</p>
<ul>
<li><a href="#all-of-and-any-of-conditions">Added conditions <code class="language-plaintext highlighter-rouge">allOf</code> and <code class="language-plaintext highlighter-rouge">anyOf</code></a></li>
<li><a href="#add-checks-for-cookies">Added checks for cookies</a></li>
<li><a href="#update-webdrivermanager">Updated WebDriverManager</a></li>
<li><a href="#support-tspan-in-svg">Fixed support for <code class="language-plaintext highlighter-rouge"><tspan></code> in SVG</a>
<p><br /></p>
</li>
</ul>
<h3 id="all-of-and-any-of-conditions">Added conditions <code class="language-plaintext highlighter-rouge">allOf</code> and <code class="language-plaintext highlighter-rouge">anyOf</code></h3>
<p>Now you can check one of conditions (OR):</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#president"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">anyOf</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Lowlife"</span><span class="o">),</span> <span class="n">text</span><span class="o">(</span><span class="s">"Cowardly bum"</span><span class="o">)));</span>
</code></pre></div></div>
<p>(in fact, Selenide already had method <code class="language-plaintext highlighter-rouge">Condition.or</code> for the same purpose, but <code class="language-plaintext highlighter-rouge">anyOf</code> seems to be easier to use).</p>
<p>Also, you can check all conditions (AND):</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#president"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">allOf</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"a catastrophic character"</span><span class="o">),</span> <span class="n">text</span><span class="o">(</span><span class="s">"another six years of this cowardly bum in power"</span><span class="o">)));</span>
</code></pre></div></div>
<p>(in fact, it’s the same as just <code class="language-plaintext highlighter-rouge">$("#president").shouldHave(text(..), text(..))</code>,
but the result of <code class="language-plaintext highlighter-rouge">allOf</code> can be extracted to a variable or method and reused, thus creating your own DSL).</p>
<p>Thanks to <a href="https://github.com/evpl">Evgenii Plugatar</a> and <a href="https://github.com/selenide/selenide/pull/2368">PR 2368</a>.</p>
<p><br /></p>
<h3 id="add-checks-for-cookies">Added checks for cookies</h3>
<p>Now you can check cookies in browser:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">Selenide</span><span class="o">.</span><span class="na">webdriver</span><span class="o">;</span>
<span class="n">webdriver</span><span class="o">().</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">cookie</span><span class="o">(</span><span class="s">"session_id"</span><span class="o">));</span>
<span class="n">webdriver</span><span class="o">().</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">cookie</span><span class="o">(</span><span class="s">"session_id"</span><span class="o">,</span> <span class="s">"1234567890"</span><span class="o">));</span>
<span class="n">webdriver</span><span class="o">().</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">cookie</span><span class="o">(</span><span class="s">"session_id"</span><span class="o">,</span> <span class="s">"1234567890"</span><span class="o">,</span> <span class="nc">Duration</span><span class="o">.</span><span class="na">ofSeconds</span><span class="o">(</span><span class="mi">10</span><span class="o">)));</span>
</code></pre></div></div>
<p>With built-in waiting, custom timeout, automated screenshot - everything you like.</p>
<p>Thanks to <a href="https://github.com/adorne">adorne</a> for <a href="https://github.com/selenide/selenide/pull/2367">PR 2367</a>.</p>
<p><br /></p>
<h3 id="update-webdrivermanager">Updated WebDriverManager from 5.4.0 to 5.4.1</h3>
<p>Among others, it has support for Chrome 115 which caused a problem for many users.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2374">PR 2374</a>.</p>
<p>P.S. On macOS, Chrome 115 still causes a error:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SessionNotCreatedException: Could not start a new session.
Response code 500.
Message: unknown error: cannot find Chrome binary
</code></pre></div></div>
<p>It’s a known <a href="https://github.com/GoogleChromeLabs/chrome-for-testing/issues/30">chromedriver bug</a>. They promised to fix it soon.</p>
<p><br /></p>
<h3 id="support-tspan-in-svg">Fixed support for <code class="language-plaintext highlighter-rouge"><tspan></code> in SVG</h3>
<p>Have you ever checked texts inside SVG? Me neither. And it turns out SVG can contain texts!</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt"><svg></span>
<span class="nt"><text</span> <span class="na">x=</span><span class="s">"10"</span> <span class="na">y=</span><span class="s">"30"</span> <span class="na">class=</span><span class="s">"small"</span><span class="nt">></span>
People want to see <span class="nt"><tspan></span>gratitude<span class="nt"></tspan></span>.
<span class="nt"></text></span>
<span class="nt"><text</span> <span class="na">x=</span><span class="s">"10"</span> <span class="na">y=</span><span class="s">"60"</span> <span class="na">class=</span><span class="s">"small"</span><span class="nt">></span>
We are not <span class="nt"><tspan></span>Amazon<span class="nt"></tspan></span> warehouse.
<span class="nt"></text></span>
<span class="nt"><text</span> <span class="na">x=</span><span class="s">"10"</span> <span class="na">y=</span><span class="s">"90"</span> <span class="na">class=</span><span class="s">"small"</span><span class="nt">></span>
Thank you, <span class="nt"><tspan></span>Ben Wallace<span class="nt"></tspan></span>!
<span class="nt"></text></span>
<span class="nt"></svg></span>
</code></pre></div></div>
<p>Now you can check these texts again:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$$</span><span class="o">(</span><span class="s">"svg tspan"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">texts</span><span class="o">(</span><span class="s">"gratitude"</span><span class="o">,</span> <span class="s">"Amazon"</span><span class="o">,</span> <span class="s">"Ben Wallace"</span><span class="o">));</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/2377">issue 2377</a> and <a href="https://github.com/selenide/selenide/pull/2379">PR 2379</a>.</p>
<p><br />
<br /></p>
<center>
<img src="/images/2023/07/ben-wallace.png" width="600" />
</center>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.16.02023-07-02T00:00:00+00:00https://selenide.org/2023/07/02/selenide-6.16.0
<p>Good night!</p>
<blockquote>
<p>I have an offer for you that you shouldn’t refuse.</p>
</blockquote>
<p>Upgrade to <a href="https://github.com/selenide/selenide/milestone/185?closed=1">Selenide 6.16.0</a>!</p>
<ul>
<li><a href="#speedup-collection-checks">Speed up collection checks</a></li>
<li><a href="#improve-collections-error-messages">Error messages in collection checks</a></li>
<li><a href="#new-date-checks">New date checks <code class="language-plaintext highlighter-rouge">date(...)</code> and <code class="language-plaintext highlighter-rouge">datetime(...)</code></a></li>
<li><a href="#set-date-time-value">New methods for setting time</a></li>
<li><a href="#full-stacktrace-in-soft-asserts">Full stacktrace in soft asserts</a></li>
<li><a href="#improve-basic-auth-in-chromium-browsers">BasicAuth in Chromium browsers</a></li>
<li><a href="#multiple-domains-in-basic-auth">Multiple domains in BasicAuth</a></li>
<li><a href="#fix-double-click-in-appium">Fixed <code class="language-plaintext highlighter-rouge">$.doubleClick()</code> in Appium</a></li>
<li><a href="#screenshot-before-after-each">Take screenshot earlier</a></li>
<li><a href="#update-dependencies">Updated dependencies</a></li>
<li><a href="#news">News</a>
<p><br /></p>
</li>
</ul>
<h3 id="speedup-collection-checks">Speed up collection checks</h3>
<p>Here is the coolness!</p>
<p>One of basic Selenide features is collection checks. With just one line you can check a bunch of elements:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$$</span><span class="o">(</span><span class="s">"option"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">texts</span><span class="o">(</span><span class="s">"Gandalf"</span><span class="o">,</span> <span class="s">"Gendalf"</span><span class="o">,</span> <span class="s">"Gondalf"</span><span class="o">))</span>
</code></pre></div></div>
<p>But such a check can <strong>take a significant time</strong> in case of big collections.</p>
<p>For example, if a page has 1000 <code class="language-plaintext highlighter-rouge"><option></code> elements, that check takes ~3 seconds on my machine.<br />
The slowness is due to the fact that Selenide fetches the text of each element separately.
1000 webdriver calls, even very fast ones, takes its time.</p>
<p>It’s time to speed up those checks!</p>
<p>Now Selenide fetches texts of all 1000 elements <strong>with a single webdriver call</strong> using JavaScript.</p>
<blockquote>
<p>Now that check takes 200ms instead of 3 seconds.<br />
It became 15 times faster!<br />
<em>That’s crazy.</em></p>
</blockquote>
<p>P.S. For Appium and other webdriver not supporting JS, Selenide will fall back to the old implementation
(fetches texts one-by-one). At least it’s not worse than before.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2362">PR 2362</a>.</p>
<p><br /></p>
<h3 id="improve-collections-error-messages">Improved error messages in collection checks</h3>
<p>During the previous refactoring, we improved error message for collections. Now Selenide provides a more detailed error
of which element didn’t meet the conditions:</p>
<p>For example, this check:</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">".number"</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">"On"</span><span class="o">,</span> <span class="s">"Tw"</span><span class="o">,</span> <span class="s">"Thre"</span><span class="o">))</span>
</code></pre></div></div>
<p>Reported just a simple <code class="language-plaintext highlighter-rouge">"Texts mismatch"</code> message:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Texts</span> <span class="n">mismatch</span>
<span class="nl">Actual:</span> <span class="o">[</span><span class="nc">One</span><span class="o">,</span> <span class="nc">Two</span><span class="o">,</span> <span class="nc">Three</span><span class="o">]</span>
<span class="nl">Expected:</span> <span class="o">[</span><span class="nc">On</span><span class="o">,</span> <span class="nc">Tw</span><span class="o">,</span> <span class="nc">Thre</span><span class="o">]</span>
</code></pre></div></div>
<p>And now it specifies what exactly didn’t match:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Text</span> <span class="err">#</span><span class="mi">0</span> <span class="n">mismatch</span> <span class="o">(</span><span class="nl">expected:</span> <span class="s">"On"</span><span class="o">,</span> <span class="nl">actual:</span> <span class="s">"One"</span><span class="o">)</span>
<span class="nl">Actual:</span> <span class="o">[</span><span class="nc">One</span><span class="o">,</span> <span class="nc">Two</span><span class="o">,</span> <span class="nc">Three</span><span class="o">]</span>
<span class="nl">Expected:</span> <span class="o">[</span><span class="nc">On</span><span class="o">,</span> <span class="nc">Tw</span><span class="o">,</span> <span class="nc">Thre</span><span class="o">]</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/pull/2362">PR 2362</a>.</p>
<p><br /></p>
<h3 id="new-date-checks">New date checks <code class="language-plaintext highlighter-rouge">date(...)</code> and <code class="language-plaintext highlighter-rouge">datetime(...)</code></h3>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">conditions</span><span class="o">.</span><span class="na">datetime</span><span class="o">.</span><span class="na">DateConditionOptions</span><span class="o">.*;</span>
<span class="nc">LocalDate</span> <span class="n">birthday</span> <span class="o">=</span> <span class="nc">LocalDate</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="mi">2022</span><span class="o">,</span> <span class="mi">10</span><span class="o">,</span> <span class="mi">11</span><span class="o">);</span>
<span class="err">$</span><span class="o">(</span><span class="s">"#birthdate"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">date</span><span class="o">(</span><span class="n">birthday</span><span class="o">));</span>
<span class="err">$</span><span class="o">(</span><span class="s">"#birthdate"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">date</span><span class="o">(</span><span class="n">birthday</span><span class="o">,</span> <span class="s">"yyyy-MM-dd"</span><span class="o">));</span>
<span class="err">$</span><span class="o">(</span><span class="s">"#birthdate"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">dateBetween</span><span class="o">(</span><span class="n">parse</span><span class="o">(</span><span class="s">"2020-01-01"</span><span class="o">),</span> <span class="n">parse</span><span class="o">(</span><span class="s">"2023-12-31"</span><span class="o">)));</span>
<span class="err">$</span><span class="o">(</span><span class="s">"#birthdate"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">dateFormat</span><span class="o">(</span><span class="s">"yyyy-MM-dd"</span><span class="o">));</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/2268">issue 2268</a>.
Thanks to <a href="https://github.com/Au6ojlut">Maksim @Au6ojlut</a> for <a href="https://github.com/selenide/selenide/pull/2281">PR 2281</a>.</p>
<p><br /></p>
<h3 id="set-date-time-value">New methods for setting time</h3>
<p>Selenide had a method for selecting a date (<code class="language-plaintext highlighter-rouge">withDate</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">"#birthdate"</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="nc">LocalDate</span><span class="o">.</span><span class="na">of</span><span class="o">(...)));</span>
<span class="c1">// for <input type="date"></span>
</code></pre></div></div>
<p>Now we have similar methods for selecting date and time (<code class="language-plaintext highlighter-rouge">withDateTime</code>):</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#birthdate"</span><span class="o">).</span><span class="na">setValue</span><span class="o">(</span><span class="n">withDateTime</span><span class="o">(</span><span class="nc">LocalDateTime</span><span class="o">.</span><span class="na">of</span><span class="o">(...)));</span>
<span class="c1">// for <input type="datetime-local"></span>
</code></pre></div></div>
<p>or only time (<code class="language-plaintext highlighter-rouge">withTime</code>):</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="s">"#openFrom"</span><span class="o">).</span><span class="na">setValue</span><span class="o">(</span><span class="n">withTime</span><span class="o">(</span><span class="nc">LocalTime</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="mi">7</span><span class="o">,</span> <span class="mi">12</span><span class="o">)));</span>
<span class="err">$</span><span class="o">(</span><span class="s">"#closeFrom"</span><span class="o">).</span><span class="na">setValue</span><span class="o">(</span><span class="n">withTime</span><span class="o">(</span><span class="nc">LocalTime</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="mi">17</span><span class="o">,</span> <span class="mi">59</span><span class="o">,</span> <span class="mi">58</span><span class="o">)));</span>
<span class="c1">// for <input type="time"></span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/pull/2357">PR 2357</a>.</p>
<p><br /></p>
<h3 id="full-stacktrace-in-soft-asserts">Full stacktrace in soft asserts</h3>
<p>In Selenide, you can enable soft asserts mode. Then Selenide will collect several failures during a test, and throw
an exception in the end. This exception will include all collected assertion errors.</p>
<p>The problem is that Selenide didn’t show full stacktraces, so you couldn’t see the “Caused by:” part.
Now it will be shown.<br />
Be prepared for the lengthy stack traces :)</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2350">issue 2350</a> and <a href="https://github.com/selenide/selenide/pull/2354">PR 2354</a>.</p>
<p><br /></p>
<h3 id="improve-basic-auth-in-chromium-browsers">Improved BasicAuth in Chromium browsers</h3>
<p>Selenide has methods for BasicAuth authentication:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">open</span><span class="o">(</span><span class="s">"/basic-auth/hello"</span><span class="o">,</span> <span class="s">"my.test.com"</span><span class="o">,</span> <span class="s">"scott"</span><span class="o">,</span> <span class="s">"pwd123"</span><span class="o">);</span>
</code></pre></div></div>
<p>Until now, we had two BasicAuth implementations.</p>
<ol>
<li>If proxy is enabled: Selenide adds an <code class="language-plaintext highlighter-rouge">Authorization</code> header to every http request (<code class="language-plaintext highlighter-rouge">Basic YWRtaW460JrQsNC30LrQvtCy0LAg0LTRltCx0YDQvtCy0LA=</code>).</li>
<li>If proxy is disabled: Selenide adds login+password to URL (<code class="language-plaintext highlighter-rouge">https://scott:pwd123@localhost:42220/basic-auth/hello</code>).</li>
</ol>
<p>Now we have a third implementation.
If webdriver implements interface <code class="language-plaintext highlighter-rouge">org.openqa.selenium.HasAuthentication</code>, then Selenide adds login+password via this interface.
Basically it means Chromium based browsers (Chrome, Chromium, Edge).</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2336">issue 2336</a> and <a href="https://github.com/selenide/selenide/pull/2358">PR 2358</a>.</p>
<p><br /></p>
<h3 id="multiple-domains-in-basic-auth">Multiple domains in BasicAuth</h3>
<p>Until now, you could set only one domain for BasicAuth:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">open</span><span class="o">(</span><span class="s">"/basic-auth/hello"</span><span class="o">,</span> <span class="s">"my.test.com"</span><span class="o">,</span> <span class="s">"scott"</span><span class="o">,</span> <span class="s">"pwd123"</span><span class="o">);</span>
</code></pre></div></div>
<p>It doesn’t help if AUT uses multiple domains. For example, if AUT at address “https://my.test.com” opens a frame with address
“https://api.test.com” or, say, “https://api.test.com”. You can set an empty domain, but
<a href="/2022/10/07/selenide-6.9.0/#secure-authorization-header">it’s not always safe</a>.</p>
<p>Now you can set multiple domains separated by comma or “|”:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">open</span><span class="o">(</span><span class="s">"/basic-auth/hello"</span><span class="o">,</span> <span class="s">"my.test.com|auth.test.com|api.test.com"</span><span class="o">,</span>
<span class="s">"scott"</span><span class="o">,</span> <span class="s">"pwd123"</span><span class="o">);</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/pull/2358">PR 2358</a>.</p>
<p>P.S. Of course, the domain name is not used when Selenide adds the login+password just to the URL.</p>
<p><br /></p>
<h3 id="fix-double-click-in-appium">Fixed <code class="language-plaintext highlighter-rouge">$.doubleClick()</code> in Appium</h3>
<p>In a previous release we broke, and now we’ve fixed the double click in mobile phones:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span><span class="o">(</span><span class="nc">AppiumBy</span><span class="o">.</span><span class="na">xpath</span><span class="o">(</span><span class="s">".//android.widget.CheckBox"</span><span class="o">)).</span><span class="na">doubleClick</span><span class="o">();</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/2346">issue 2346</a> and <a href="https://github.com/selenide/selenide/pull/2347">PR 2347</a>.</p>
<p><br /></p>
<h3 id="screenshot-before-after-each">Take screenshot earlier</h3>
<p>Usually Selenide takes a screenshot after a test failure.<br />
BUT
If you close the browser in <code class="language-plaintext highlighter-rouge">@AfterEach</code> method, Selenide could not take the screenshot anymore:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@AfterEach</span>
<span class="kt">void</span> <span class="nf">tearDown</span><span class="o">()</span> <span class="o">{</span>
<span class="nc">Selenide</span><span class="o">.</span><span class="na">closeWebDriver</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Now Selenide will take the screenshot earlier - BEFORE all <code class="language-plaintext highlighter-rouge">@AfterEach</code> methods.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2352">issue 2352</a> and <a href="https://github.com/selenide/selenide/pull/2356">PR 2356</a>.</p>
<p><br /></p>
<h3 id="update-dependencies">Updated dependencies</h3>
<ul>
<li><a href="https://github.com/selenide/selenide/pull/2318">2319</a> use latest version of geckodriver for FF 102+</li>
<li><a href="https://github.com/selenide/selenide/pull/2328">2328</a> bump Selenium from 4.9.1 to 4.10.0</li>
<li><a href="https://github.com/selenide/selenide/pull/2324">2324</a> Bump io.appium:java-client from 8.5.0 to 8.5.1</li>
<li><a href="https://github.com/selenide/selenide/pull/2349">2349</a> Bump Netty from 4.1.93.Final to 4.1.94.Final</li>
<li>bump WebDriverManager from 5.3.3 to 5.4.0</li>
</ul>
<p><br /></p>
<h3 id="news">News</h3>
<ul>
<li>
<p>Video <a href="https://www.youtube.com/watch?v=zAhCLLX9IOc&ab_channel=TestingMiniBytes">Run Selenide Appium Test in LambdaTest</a> in blog “Testing Mini Bytes”</p>
</li>
<li>
<p>Number of monthly downloads of Selenide is still around 600 thousands!</p>
</li>
</ul>
<center>
<img src="/images/2023/07/selenide.downloads.png" width="800" />
</center>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.15.02023-05-29T00:00:00+00:00https://selenide.org/2023/05/29/selenide-6.15.0
<p>Good night!</p>
<p>We released <a href="https://github.com/selenide/selenide/milestone/184?closed=1">Selenide 6.15.0</a>
with quite serious internal changes.</p>
<ul>
<li><a href="#merge-selenide-selenoid-to-selenide">Merged project <code class="language-plaintext highlighter-rouge">selenide-selenoid</code> into <code class="language-plaintext highlighter-rouge">selenide</code></a></li>
<li><a href="#merge-selenide-appium-to-selenide">Merged project <code class="language-plaintext highlighter-rouge">selenide-appium</code> into <code class="language-plaintext highlighter-rouge">selenide</code></a></li>
<li><a href="#clicking-disable-element-fails">Click checks that element is not disabled</a></li>
<li><a href="#escape-newlines-in-report">Escape newlines in text report</a></li>
<li><a href="#combined-selectors-for-mobile-apps">Combined selectors for mobile apps</a></li>
<li><a href="#conditions-for-mobile-apps">New checks for mobile apps</a></li>
<li><a href="#new-selectors-for-mobile-apps">New selectors for mobile apps</a></li>
<li><a href="#switch-context-in-mobile-apps">Switch context in mobile apps</a></li>
<li><a href="#refactor-collection-conditions">Refactoring of CollectionCondition</a></li>
<li><a href="#news">News</a>
<p><br /></p>
</li>
</ul>
<h3 id="merge-selenide-selenoid-to-selenide">Merged project <code class="language-plaintext highlighter-rouge">selenide-selenoid</code> into <code class="language-plaintext highlighter-rouge">selenide</code></h3>
<p>This allows us to easily change and release these projects.
For you, the dependency declaration will change.</p>
<p>Instead of</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>You will need to use:</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>See <a href="https://github.com/selenide/selenide/pull/2292">PR 2292</a>.</p>
<p><br /></p>
<h3 id="merge-selenide-appium-to-selenide">Merged project <code class="language-plaintext highlighter-rouge">selenide-appium</code> into <code class="language-plaintext highlighter-rouge">selenide</code></h3>
<p>This allows us to easily change and release these projects.
For you, just the dependency version will change.</p>
<p>You will need to update <code class="language-plaintext highlighter-rouge">selenide-appium</code> from <code class="language-plaintext highlighter-rouge">2.8.1</code> to <code class="language-plaintext highlighter-rouge">6.15.0</code>.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2291">PR 2291</a>.</p>
<p><br /></p>
<h3 id="clicking-disable-element-fails">Now Click checks that the element is not disabled</h3>
<p>As you know, method <code class="language-plaintext highlighter-rouge">$.click()</code> first checks that the element is visible (more specifically, the element should be
either visible or have css property <code class="language-plaintext highlighter-rouge">opacity: 0</code>).</p>
<p>BUT until now, Selenide didn’t check that the element is <em>enabled</em>. In other words,</p>
<blockquote>
<p>Selenide did allow to click <code class="language-plaintext highlighter-rouge">disabled</code> elements.</p>
</blockquote>
<ol>
<li>Argument <strong>in favor</strong> of this decision: what if test author does want to click the disabled element and make sure that nothing happens?</li>
<li>Argument <strong>against</strong> this decision: this behavior can cause flaky tests:
<ul>
<li>the test clicks a button without waiting until the buttons gets enabled;</li>
<li>de-facto click didn’t happen (but no errors were thrown);</li>
<li>and later the test fails because the click didn’t happen (and it will be very hard to understand why the test failed).</li>
<li>or even worse: the test may remain false positive.</li>
</ul>
</li>
</ol>
<p>So now <strong>argument #2 has won</strong>. Now method <code class="language-plaintext highlighter-rouge">$.click()</code> will wait until the element gets enabled. <br />
If the element is not enabled, the click will fail.</p>
<p>Now you can shorten your tests even more:</p>
<blockquote>
<p>Replace <code class="language-plaintext highlighter-rouge">$.shouldBe(enabled).click()</code> by just <code class="language-plaintext highlighter-rouge">$.click()</code>.</p>
</blockquote>
<p>P.S. If you’re in the #1 camp, you can use <code class="language-plaintext highlighter-rouge">$.shouldBe(disabled)</code> instead of clicking.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2288">issue 2288</a>.
Thanks to <a href="https://github.com/Au6ojlut">Maksim @Au6ojlut</a> for <a href="https://github.com/selenide/selenide/pull/2290">PR 2290</a>.</p>
<p><br /></p>
<h3 id="escape-newlines-in-report">Escape newlines in text report</h3>
<p>If you tried using a multi-line string in your test:</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\n multi\n line\n world"</span><span class="o">);</span>
</code></pre></div></div>
<p>Then you might have noticed that in the report this line looked clumsy and broke the entire table.</p>
<p>Now it will look good.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2283">issue 2283</a>.
Thanks to <a href="https://github.com/Au6ojlut">Maksim @Au6ojlut</a> for <a href="https://github.com/selenide/selenide/pull/2284">PR 2284</a>.</p>
<p><br /></p>
<h3 id="combined-selectors-for-mobile-apps">Combined selectors for mobile apps</h3>
<p>When testing mobile apps, it would be convenient to use two selectors in a check: one for Android, and the other for iOS.<br />
Previously, you had to come up with helper methods or use IFs in tests.</p>
<p>Now you can use a single selector using <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">"Hello, Android user!"</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">"Hello, iOS user!"</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">"Hello, Android user!"</span><span class="o">));</span>
</code></pre></div></div>
<p><br /></p>
<h3 id="conditions-for-mobile-apps">New checks for mobile apps</h3>
<p>A similar solution for checks: now you can declare a single check for Android, and iOS using class <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">// A single element check:</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">"To do or not to do"</span>
<span class="o">));</span>
<span class="c1">// A collection check:</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">"First"</span><span class="o">,</span>
<span class="s">"Second"</span><span class="o">,</span>
<span class="s">"Third"</span>
<span class="o">));</span>
</code></pre></div></div>
<p><br /></p>
<h3 id="new-selectors-for-mobile-apps">New selectors for mobile apps</h3>
<p>We also added a bunch of selectors to find mobile elements by tag, text, substring etc.:</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">"Good"</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">"bye"</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">"ugly xpath world"</span><span class="o">)).</span><span class="na">click</span><span class="o">();</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/2300">issue 2300</a>.
Thanks to <a href="https://github.com/amuthansakthivel">Amuthan Sakthivel</a> for <a href="https://github.com/selenide/selenide-appium/pull/135">PR 135</a>.
See also <a href="https://github.com/selenide/selenide/pull/2315">PR 2315</a>.</p>
<p><br /></p>
<h3 id="switch-context-in-mobile-apps">Switch context in mobile apps</h3>
<p>Mobile apps often open some content in an embedded web browser (WebView). Sometimes mobile apps work entire in WebView.
When testing such apps, you often need to switch between “native” and “web” context.</p>
<p>Now we have convenient methods to switch between contexts:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Here we are in the "native" context</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">// Oops, and we're already in the "web" context:</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>See <a href="https://github.com/selenide/selenide/pull/2308">PR 2308</a>.<br />
Thanks to <a href="https://github.com/amuthansakthivel">Amuthan Sakthivel</a> for <a href="https://github.com/selenide/selenide-appium/pull/149">PR 149</a>.</p>
<p><br /></p>
<h3 id="refactor-collection-conditions">Refactoring of CollectionCondition</h3>
<p>We have changed the internal structure of collection conditions (class <code class="language-plaintext highlighter-rouge">CollectionCondition</code>).</p>
<p>If you wanted to create a <a href="https://github.com/selenide/selenide/blob/main/src/test/java/integration/collections/CustomCollectionConditionTest.java">custom collection condition</a>,
You had to implement method <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"><</span><span class="nc">WebElement</span><span class="o">></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">-></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">-></span> <span class="n">x</span> <span class="o">&&</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">".moron"</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>This <code class="language-plaintext highlighter-rouge">test</code> method will stay for some time (for backward compatibility),
but the <strong>recommended method</strong> now will be <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"><</span><span class="nc">WebElement</span><span class="o">></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"><</span><span class="nc">String</span><span class="o">></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">-></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">-></span> <span class="n">x</span> <span class="o">&&</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">".moron"</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="what-does-it-give-us">What does it give us?</h3>
<p>In the future, it will open up opportunities for us to improve collection checks:</p>
<ol>
<li>It allows us to greatly speed up the checks: for example, quickly get the texts of all elements with just one JS call.</li>
<li>In the error message, we can write “actual texts at the moment of last check” instead of “actual texts at the moment of error message generation”.
The same problem for a single element was <a href="/2021/09/28/selenide-5.25.0/#actual-value-at-the-moment-of-last-check">described here</a>.
Now it’s the same for collections.</li>
</ol>
<p>See <a href="https://github.com/selenide/selenide/pull/2312">PR 2312</a> and <a href="https://github.com/selenide/selenide/pull/2307">PR 2307</a>.</p>
<p><br /></p>
<h3 id="news">News</h3>
<ul>
<li>Video <a href="https://www.youtube.com/watch?v=M--_ziTZPQQ&ab_channel=kanezi">Testing Spring with Selenide</a> by kanezi</li>
<li>Video series on Testing Mini Bytes: <a href="https://www.youtube.com/watch?v=UQWQJ3dhgVI&ab_channel=TestingMiniBytes">Selenide + Allure = Beautiful HTML Reports</a></li>
<li>Post <a href="https://creatingvalue.substack.com/p/why-we-chose-selenide-over-selenium">Why we chose Selenide over Selenium</a> by Amuthan Sakthivel</li>
<li>A historical moment: <a href="https://pikabu.ru/story/selenium_selenide_i_selenoid_8376039">the first meme about Selenide</a></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/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.14.02023-05-08T00:00:00+00:00https://selenide.org/2023/05/08/selenide-6.14.0
<p>Good evening!</p>
<p>Good news: we have released <a href="https://github.com/selenide/selenide/milestone/181?closed=1">Selenide 6.14.0</a>.</p>
<p>It contains some changes that look minor, but might break something in your tests.
<em>That’s why I highly recommend to <strong>upgrade now</strong></em></p>
<ul>
<li><a href="#speedup-debug">Sped up debugging</a></li>
<li><a href="#remove-flag--no-sandbox">Removed flag <code class="language-plaintext highlighter-rouge">--no-sandbox</code></a></li>
<li><a href="#add-step-method">Added method <code class="language-plaintext highlighter-rouge">step</code> for reports</a></li>
<li><a href="#drag-and-drop-with-options">Added method <code class="language-plaintext highlighter-rouge">$.dragAndDrop(DragAndDropOptions)</code></a></li>
<li><a href="#allow-negative-browser-position">Browser out of screen</a></li>
<li><a href="#update-dependencies">Updated dependencies</a></li>
<li><a href="#news">News</a></li>
<li><a href="#statistics">Statistics</a>
<p><br /></p>
</li>
</ul>
<h3 id="speedup-debug">Speed up debugging</h3>
<p>When you are debugging a test and stop at a breakpoint, sometimes IDE is rendering very slowly page object fields.
In this state IDE can hang for quite a long time:</p>
<p><img src="/images/2023/05/selenide-debug.slow.png" alt="Selenide. debug. slow." width="600px" /></p>
<p>The reason is that Selenide makes multiple webdriver calls trying to get elements’ tag names, texts and attributes.
As a result, you will see the most actual detailed information after some time:</p>
<p><img src="/images/2023/05/selenide-debug.slow.result.png" alt="Selenide. debug. slow. result." width="600px" /></p>
<p>Now this process will be significantly faster. Selenide will not call webdriver anymore, but just show locator:</p>
<p><img src="/images/2023/05/selenide-debug.fast.png" alt="Selenide. debug. slow. result." width="600px" /></p>
<p>But be informed that format of <code class="language-plaintext highlighter-rouge">$.toString()</code> / <code class="language-plaintext highlighter-rouge">$$.toString()</code> will change. Who knows, probably it might break your tests.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2253">issue 2253</a>.
and <a href="https://github.com/selenide/selenide/pull/2269">PR 2269</a>.</p>
<blockquote>
<p>But don’t worry, it’s all only about debugging.
In case of test failure, you will still receive the full element information with blackjack and screenshooters.</p>
</blockquote>
<p><br /></p>
<h3 id="remove-flag--no-sandbox">Removed Chrome argument <code class="language-plaintext highlighter-rouge">--no-sandbox</code></h3>
<p>I personally don’t see any difference, whether I run tests with or without this argument.</p>
<p>But</p>
<ol>
<li>Some users complain that Chrome cannot start in Docker <em>without</em> argument <code class="language-plaintext highlighter-rouge">--no-sandbox</code>;</li>
<li>Other users complain that Chrome, when started <em>with</em> argument <code class="language-plaintext highlighter-rouge">--no-sandbox</code>, doesn’t stop - and chrome process hangs forever in background and eats CPU. But it seems to happen only on Windows (?)</li>
</ol>
<p>After years of hesitations, we decided to remove this argument <code class="language-plaintext highlighter-rouge">--no-sandbox</code> by default.
Users of type #1</p>
<ul>
<li>can easily detect the problem (chrome wont start)</li>
<li>can easily add this argument in their tests:
<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>See <a href="https://github.com/selenide/selenide/issues/2270">issue 2270</a> and <a href="https://github.com/selenide/selenide/pull/2271">PR 2271</a>.</p>
<p><br /></p>
<h3 id="add-step-method">Added method <code class="language-plaintext highlighter-rouge">step</code> for reports</h3>
<p>If you use Selenide built-in report (<code class="language-plaintext highlighter-rouge">TextReport</code>), now you can group actions using new method <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">,()->{</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">,()->{</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>These “steps” will be visually distinguished in the report:</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>By the way, those steps can be embedded into each other.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2172">issue 2172</a>.
Thanks to <a href="https://github.com/Au6ojlut">Maksim @Au6ojlut</a> for <a href="https://github.com/selenide/selenide/pull/2250">PR 2250</a>.</p>
<p><br /></p>
<h3 id="drag-and-drop-with-options">Added method <code class="language-plaintext highlighter-rouge">$.dragAndDrop(DragAndDropOptions)</code> with options</h3>
<p>Now method <code class="language-plaintext highlighter-rouge">$.dragAndDrop</code> acquired a more logical sound: first “what”, then “where” and finally, “how”.</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>Thanks to <a href="https://github.com/Au6ojlut">Maksim @Au6ojlut</a> for <a href="https://github.com/selenide/selenide/pull/2245">PR 2245</a>.</p>
<p><br /></p>
<h3 id="allow-negative-browser-position">Allow to set browser position out of screen</h3>
<p>We fixed a minor bug that didn’t allow setting negative values to browser position:</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>I have no idea why this might be useful, but now it’s possible.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2258">issue 2258</a> and <a href="https://github.com/selenide/selenide/pull/2259">PR 2259</a>.</p>
<p><br /></p>
<h3 id="support-edge-binary-location">Allow setting path to Edge browser binary</h3>
<p>Selenide has setting <code class="language-plaintext highlighter-rouge">Configuration.browserBinary</code> that allows you set path to browser binary
(just in case: in most cases, you <em>don’t need to set it</em>).</p>
<p>Previously, this setting was not supported for Edge browser. Now it’s supported.</p>
<p>Thanks to <a href="https://github.com/vlad8x8">Vladislav Velichko</a> for <a href="https://github.com/selenide/selenide/pull/2267">PR 2267</a>.</p>
<p><br /></p>
<h3 id="update-dependencies">Updated dependencies</h3>
<ul>
<li><a href="https://github.com/selenide/selenide/pull/2277">Selenium 4.9.1</a> - see <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">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">News</h3>
<ul>
<li>Series of tutorials <a href="https://www.youtube.com/playlist?list=PLFGzDEkV3ACu0i-Gd_whXsspqDlmP3ymP">Selenide Java with Cucumber</a> by <a href="https://www.youtube.com/@TechProEducationUS">TechPro Education</a></li>
</ul>
<h3 id="statistics">Statistics</h3>
<p>Number of monthly downloads of Selenide exceeded 600 thousands!</p>
<center>
<img src="/images/2023/04/selenide.downloads.jpg" width="800" />
</center>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.13.02023-04-04T00:00:00+00:00https://selenide.org/2023/04/04/selenide-6.13.0
<p>Good night!</p>
<p>Today we have a big major release <a href="https://github.com/selenide/selenide/milestone/177?closed=1">Selenide 6.13.0</a>.</p>
<ul>
<li><a href="#add-method-cached">Added method <code class="language-plaintext highlighter-rouge">$.cached()</code></a></li>
<li><a href="#mock-response-with-http-status">Added http status for server response mock</a></li>
<li><a href="#add-method-in-new-browser">Added method <code class="language-plaintext highlighter-rouge">inNewBrowser</code> for running code in a new browser</a></li>
<li><a href="#add-method-doubleclick-with-options">Added method <code class="language-plaintext highlighter-rouge">$.doubleClick(options)</code></a></li>
<li><a href="#add-condition-inner-text">Added condition <code class="language-plaintext highlighter-rouge">$.shouldHave(innerText())</code></a></li>
<li><a href="#add-condition-attributes">Added collection condition <code class="language-plaintext highlighter-rouge">$$.shouldHave(attributes(...))</code></a></li>
<li><a href="#clear-error-message-in-select">Clear error message in methods <code class="language-plaintext highlighter-rouge">$.select*()</code></a></li>
<li><a href="#fix-method-sublist">Fixed bug in <code class="language-plaintext highlighter-rouge">$$.subList()</code></a></li>
<li><a href="#update-dependencies">Updated dependencies</a></li>
<li><a href="#news">News</a>
<p><br /></p>
</li>
</ul>
<h3 id="add-method-cached">Added method <code class="language-plaintext highlighter-rouge">$.cached()</code></h3>
<p>Sometimes you need to write quite complex code for finding an element.<br />
And it might work <strong>slowly</strong>, especially if you find it from a long collection applying specific filtering.<br />
Something like this:</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>Every call to <code class="language-plaintext highlighter-rouge">target</code> is apparently slow.</p>
<p>Now you can speed up such tests by caching the <code class="language-plaintext highlighter-rouge">target</code> element:</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>Obviously, you can cache it only if you are sure that it’s not updated/reloaded during the test. <br />
If it still gets reloaded, you will get the famous <code class="language-plaintext highlighter-rouge">StaleElementReferenceException</code>.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2171">issue 2171</a>,
<a href="https://github.com/selenide/selenide/issues/1927">issue 1927</a>
and <a href="https://github.com/selenide/selenide/pull/2189">PR 2189</a>.</p>
<p><br /></p>
<h3 id="mock-response-with-http-status">Added http status to server response mock</h3>
<p>Selenide has method for mocking a server response:</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">-></span> <span class="s">"{role: admin}"</span><span class="o">);</span>
</code></pre></div></div>
<p>It allowed to mock only response body, response status was always 200 (“OK”).<br />
Now you can set another status too:</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">-></span> <span class="s">"{role: looser}"</span><span class="o">);</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/2227">issue 2227</a> and <a href="https://github.com/selenide/selenide/pull/2234">PR 2234</a>.</p>
<p><br /></p>
<h3 id="add-method-in-new-browser">Added method <code class="language-plaintext highlighter-rouge">inNewBrowser</code> for running a code snippet in a new browser</h3>
<p>Sometimes you want to run a code block in a new browser.</p>
<blockquote>
<p>Usually I say it’s a bad practice. Actions like data preparation etc. should not be performed via UI
(we are testing UI -> we cannot trust UI). Instead, you should use some reliable way: using API, query to database etc.</p>
</blockquote>
<p>Still, for this purpose we have <a href="/2019/10/16/selenide-5.4.0/#add-method-using">method <code class="language-plaintext highlighter-rouge">using</code></a>. But to use it, you
need to open your custom webdriver with some specific settings. But what if you don’t specific settings? What if you
need a standard webdriver with usual Selenide settings - just a new instance of browser?</p>
<p>Now you can use method <code class="language-plaintext highlighter-rouge">inNewBrowser</code> for that:</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">-></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>See <a href="https://github.com/selenide/selenide/issues/2213">issue 2213</a> and <a href="https://github.com/selenide/selenide/pull/2236">PR 2236</a>.</p>
<p><br /></p>
<h3 id="add-method-doubleclick-with-options">Added method <code class="language-plaintext highlighter-rouge">$.doubleClick(options)</code></h3>
<p>We already had method <code class="language-plaintext highlighter-rouge">$.doubleClick()</code> which could only click the center of given element.
Now it got an advanced bro with <code class="language-plaintext highlighter-rouge">options</code> parameter. The options are the same as for usual <code class="language-plaintext highlighter-rouge">$.click</code> method:</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>See <a href="https://github.com/selenide/selenide/issues/2133">issue 2133</a>.
Thanks to <a href="https://github.com/aakachurin">aakachurin</a> for <a href="https://github.com/selenide/selenide/pull/2135">PR 2135</a>.</p>
<p><br /></p>
<h3 id="add-condition-inner-text">Added condition <code class="language-plaintext highlighter-rouge">$.shouldHave(innerText())</code></h3>
<p>It allows to check texts of hidden elements.</p>
<blockquote>
<p>Probably it’s a bad idea: if real users cannot see the element then you don’t need to test it.</p>
</blockquote>
<p>But if you really want, you can now use condition <code class="language-plaintext highlighter-rouge">innerText</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">"#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">"Can you see the hidden text?"</span><span class="o">));</span>
<span class="c1">// Usual $("#theHiddenElement").text() returns an empty string here: "";</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/2220">issue 2220</a> and <a href="https://github.com/selenide/selenide/pull/2223">PR 2223</a>.</p>
<p><br /></p>
<h3 id="add-condition-attributes">Added collection condition <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>See <a href="https://github.com/selenide/selenide/issues/2091">issue 2091</a>.
Thanks to <a href="https://github.com/AlexLAA">Alexey Lakovych</a> for <a href="https://github.com/selenide/selenide/pull/2091">PR 2091</a>.
See also <a href="https://github.com/selenide/selenide/pull/2230">PR 2230</a>.</p>
<p><br /></p>
<h3 id="clear-error-message-in-select">Added a clear error message in methods <code class="language-plaintext highlighter-rouge">$.select*()</code></h3>
<p>Selenide has convenient methods for working with dropdowns:</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>Recently we <a href="/2022/11/21/selenide-6.10.0/#select-options-using-javascript">changed their implementation to JavaScript</a> - it’s faster and stable.</p>
<p>But it turned out that if you mistakenly call such a method for a non-<code class="language-plaintext highlighter-rouge"><select></code>, a very incomprehensible error took off:</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">--></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>Now this error message will be clear:</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>See <a href="https://github.com/selenide/selenide/issues/2231">issue 2231</a> and <a href="https://github.com/selenide/selenide/pull/2233">PR 2233</a>.</p>
<h3 id="fix-method-sublist">Fixed bug in method <code class="language-plaintext highlighter-rouge">$$.subList()</code></h3>
<p>As you know, Selenide has methods for checking the whole collection of elements with one line:</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>Method <code class="language-plaintext highlighter-rouge">$$</code> returns an object <code class="language-plaintext highlighter-rouge">ElementsCollection</code>, which (unfortunately) is inherited from <code class="language-plaintext highlighter-rouge">AbstractList<SelenideElement></code>.
Thus, it inherits few unexpected methods that we initially didn’t think about.</p>
<p>One of such methods is <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>This iterator returns two, not three elements. It truncates the last element. Oops… <code class="language-plaintext highlighter-rouge">¯\_(ツ)_/¯</code></p>
<p>Now this bug is fixed. Iterator will return all elements.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2239">issue 2239</a> and <a href="https://github.com/selenide/selenide/pull/2240">PR 2240</a>.</p>
<p><br /></p>
<h3 id="update-dependencies">Updated dependencies</h3>
<ul>
<li>bump Selenium from 4.8.1 to 4.8.3 – see <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">News</h3>
<p>Today we have few videos about Selenide</p>
<ul>
<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&ab_channel=Jfokus">Flaky tests</a></li>
<li><a href="https://www.youtube.com/watch?v=wN45Qla66-o&list=PLFGoYjJG_fqrvWt1FfHqKoREQmSPxazBq&ab_channel=NaveenAutomationLabs">Selenide channel</a> by NaveenAutomationLabs</li>
</ul>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.13.02023-04-01T00:00:00+00:00https://selenide.org/2023/04/01/selenide-6.13.0
<p>Hi all!</p>
<p>Wow, today we released <strong>Selenide 6.13.0</strong></p>
<ul>
<li><a href="#banners-support">Banners support</a></li>
<li><a href="#news">News</a>
<p><br /></p>
</li>
</ul>
<h3 id="banners-support">Banners support</h3>
<h4 id="the-problem">The problem</h4>
<p>People often asked me: “What can I do if during a test execution, a banner can appear on the screen (or any other unexpected element)?”</p>
<p>Such a banner can cover other elements, can hide some important button - and your test might occasionally get broken.</p>
<blockquote>
<p><a href="https://ru.selenide.org/2019/12/02/advent-calendar-how-to-abuse-selenide/">I’ve always scolded these questions</a>
and insisted that you should control your testing environment. You should dictate when the banner should appear, and when it should not.</p>
</blockquote>
<p>But this question was too popular. In the end, we decided to suggest a solution in Selenide.</p>
<p>Now you can all new method <code class="language-plaintext highlighter-rouge">Selenide.onBanner()</code> in the beginning of your test:</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="how-it-works">How it works</h4>
<p>By default, this method adds a listener to webdriver. Before every click or check, this listener will ask browser if
there exists an element with given selector <code class="language-plaintext highlighter-rouge">"#pizzaAds"</code>. If it exists, Selenide will try to close it by clicking
button <code class="language-plaintext highlighter-rouge">".btn-close"</code>.</p>
<p>We called this method <code class="language-plaintext highlighter-rouge">POLL</code>. It’s very simple and stable, but it’s also relatively slow.
Because Selenide needs to ask from browser many-many times if the banner has appeared. Every request takes some time.</p>
<p><br /></p>
<h4 id="alternative-methods">Alternative methods</h4>
<p>That’s why we added 2 alternative methods for checking if the banner exists.
You can enable them by a global setting:</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">// the default mode</span>
<span class="c1">// Listens DOM change events via 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">// Works only in Chromium-based browsers</span>
<span class="c1">// Sends current page html to ChatGPT and asks if it contains a banner</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>Or you can set mode as a parameter using <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="custom-logic">Custom logic</h4>
<p>There is a more generic option if you need to implement some custom logic for handling banner.
For example, you might need to find some info inside the banner before closing it:</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">-></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">"Your password has been changed."</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>Feel free to try, experiment, register issues on GitHub. Feel free to suggest your algorithms for banner detection.</p>
<blockquote>
<p>Let’s unite against banners!</p>
</blockquote>
<h3 id="news">News</h3>
<p>Today we have few video about Selenide:</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=GwHG550moGc">ChatGPT: How to download file in Selenide</a></li>
<li>Channel <a href="https://www.youtube.com/watch?v=SohZfPKicZQ&ab_channel=OlehPendrak">Selenide - UI Automation Tool</a> by Naveen AutomationLabs</li>
<li><a href="https://www.youtube.com/watch?v=18J2_4a4Cl4&ab_channel=Jfokus">Flaky tests</a> - JFokus conference, Stockholm, 8.02.2023</li>
</ul>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.12.42023-03-23T00:00:00+00:00https://selenide.org/2023/03/23/selenide-6.12.4
<p>Good evening!</p>
<p>We released <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">Workaround for Chromedriver</a></li>
<li><a href="#support-jdk-http-client">Support for jdk-http-client</a></li>
<li><a href="#restore-proxy-after-using">Fixed $.download(PROXY) after “using”</a></li>
<li><a href="#fix-clear-when-element-disappears">Fixed $.clear() when element disappears</a></li>
<li><a href="#update-dependencies">Updated dependencies</a></li>
<li><a href="#release-selenide-appium">Released selenide-appium 2.7.0</a></li>
<li><a href="#release-selenide-selenoid">Released selenide-selenoid 2.3.6</a></li>
<li><a href="#news">News</a>
<p><br /></p>
</li>
</ul>
<h3 id="workaround-for-chromedriver-bug">Workaround for Chromedriver</h3>
<p>Reminder: if you still are looking for a solution for</p>
<blockquote>
<p>Invalid Status code=403 text=Forbidden</p>
</blockquote>
<p>then it was released in <a href="/2023/03/09/selenide-6.12.2/">Selenide 6.12.2</a>.</p>
<p><br /></p>
<h3 id="support-jdk-http-client">Added support for <code class="language-plaintext highlighter-rouge">jdk-http-client</code> as a replacement for <code class="language-plaintext highlighter-rouge">netty-client</code></h3>
<p>By default, Selenide still uses old good <code class="language-plaintext highlighter-rouge">netty-client</code>, but if you wish to<br />
<a href="https://www.selenium.dev/blog/2022/using-java11-httpclient/">upgrade to jdk-http-client</a>,
now you can easily do that:</p>
<ol>
<li>Add dependency:<br />
<code class="language-plaintext highlighter-rouge">org.seleniumhq.selenium:selenium-http-jdk-client:$seleniumVersion</code></li>
<li>Add system property before opening a browser: <br />
<code class="language-plaintext highlighter-rouge">System.setProperty("webdriver.http.factory", "jdk-http-client");</code></li>
</ol>
<p>See <a href="https://github.com/selenide/selenide/issues/2215">issue 2215</a>
and <a href="https://github.com/selenide/selenide/pull/2216">PR 2216</a>.</p>
<p><br /></p>
<h3 id="restore-proxy-after-using">Restored proxy after using <code class="language-plaintext highlighter-rouge">using</code></h3>
<p>It’s almost the same problem as <a href="https://github.com/selenide/selenide/issues/2202">issue 2202</a>,
but with Selenide built-in proxy.</p>
<p>If you enabled a proxy in your tests, once you used method <code class="language-plaintext highlighter-rouge">using</code>, the proxy disappeared.
The following downloading of files (or any other featured you used proxy for) didn’t work anymore.</p>
<p>Now <code class="language-plaintext highlighter-rouge">using</code> method has been fixed. See more details about this <a href="/2019/10/16/selenide-5.4.0/#add-method-using">very convenient method <code class="language-plaintext highlighter-rouge">using</code></a>.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2208">PR 2208</a> and
<a href="https://github.com/selenide/selenide/pull/2209">PR 2209</a>.</p>
<p><br /></p>
<h3 id="fix-clear-when-element-disappears">Fixed <code class="language-plaintext highlighter-rouge">$.clear()</code> when element disappears</h3>
<p>As you know, Selenide has method <code class="language-plaintext highlighter-rouge">$("input").clear()</code> that clears given input field.<br />
But it could fail in one specific situation: when the input disappears as a result of clearing.<br />
At this moment, method <code class="language-plaintext highlighter-rouge">$.clear()</code> tried to trigger <code class="language-plaintext highlighter-rouge">change</code> event on this input - and failed.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2207">issue 2207</a> and
<a href="https://github.com/selenide/selenide/pull/2221">PR 2221</a>.</p>
<p><br /></p>
<h3 id="update-dependencies">Updated 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">Released <code class="language-plaintext highlighter-rouge">selenide-appium:2.7.0</code></h3>
<ul>
<li>Added scroll up/down for mobile apps (#139)</li>
<li>Fixed method <code class="language-plaintext highlighter-rouge">terminateApp</code> (#146)</li>
<li>Upgraded to Selenide 6.12.4 (#143)</li>
</ul>
<p>See <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">Released <code class="language-plaintext highlighter-rouge">selenide-selenoid:2.3.6</code></h3>
<ul>
<li>Upgraded to Selenide 6.12.4</li>
</ul>
<p>See <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>Finally, I have a video about <a href="https://www.youtube.com/watch?v=18J2_4a4Cl4&ab_channel=Jfokus">Flaky tests in English</a> - JFokus conference, Stockholm, 8.02.2023</li>
</ul>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.12.22023-03-09T00:00:00+00:00https://selenide.org/2023/03/09/selenide-6.12.2
<p>Hi all!</p>
<p>Urgently update to <a href="https://github.com/selenide/selenide/milestone/178?closed=1">Selenide 6.12.2</a>!</p>
<p>It has one important workaround for Chromedriver 111 issue:</p>
<blockquote>
<p>Invalid Status code=403 text=Forbidden</p>
</blockquote>
<h3 id="whats-the-problem">What’s the problem?</h3>
<p>Recently a new version of Chrome and Chromedriver was released: 111.</p>
<p>People who did upgrade their browser unexpectedly started getting test failures.<br />
Test tried to open the browser. The browser window appeared, but webdriver received an exception, and could not do
any following actions. In the end, test could not even close that browser!</p>
<p>In logs, you could read only messages like this:</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>Although it’s a <a href="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4361">bug in chromedriver</a>,
it had a simple workaround, and we decided to add it to Selenide to avoid a bigger hassle in QA world.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2192">issue 2192</a> and
<a href="https://github.com/selenide/selenide/pull/2194">PR 2194</a>.</p>
<blockquote>
<p>We recommend you upgrading to <a href="/2023/03/22/selenide-6.12.4/#support-jdk-http-client">HttpClient</a>.
Yes, it requires Java11+, but has better support etc.</p>
</blockquote>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.12.02023-02-24T00:00:00+00:00https://selenide.org/2023/02/24/selenide-6.12.0
<p>Hello!</p>
<p>On this tragic and festive day, we released
<a href="https://github.com/selenide/selenide/milestone/173?closed=1">Selenide 6.12.0</a>.</p>
<p>It doesn’t contain any new features, but it introduces new headless mode that might affect your tests.</p>
<ul class="blogpost-menu">
<li><a href="#new-headless-mode">New headless mode</a></li>
<li><a href="#improve-logs-when-downloading-file">Improve logging when downloading files</a></li>
<li><a href="#improve-download-in-edge">Improved downloading files in Edge on Windows</a></li>
<li><a href="#update-dependencies">Updated dependencies</a></li>
<li><a href="#rename-master-to-main">Renamed master to main</a></li>
</ul>
<p><br /></p>
<h3 id="new-headless-mode">New headless mode</h3>
<p>In Chromium browsers, a “new headless” mode has been recently introduced.
Read more details <a href="https://developer.chrome.com/articles/new-headless/">in their blog</a>.</p>
<p>Shortly said, it’s a better headless mode that should fix all problems of the “old headless”.</p>
<p>In theory, you can still switch between the old and new headless modes.
But in practice, you will have to switch to a new one.
Because after last Chrome and Edge update, downloading files in the old headless mode stopped working.</p>
<p>Starting from Selenide 6.12.0, the new headless mode will be enabled by default.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2104">issue 2104</a>.
Thanks to <a href="https://github.com/BorisOsipov">Boris Osipov</a> for <a href="https://github.com/selenide/selenide/pull/2105">PR 2105</a>
and <a href="https://github.com/selenide/selenide/pull/2169">PR 2169</a>.</p>
<p><br /></p>
<h3 id="improve-logs-when-downloading-file">Improve logging when downloading files</h3>
<p>If file downloading failed (especially using method <code class="language-plaintext highlighter-rouge">FOLDER</code>), it’s sometimes hard to understand why it failed.<br />
Now we improved logging inside of method <code class="language-plaintext highlighter-rouge">$.download()</code>, so the debugging should become easier.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2167">PR 2167</a>.</p>
<p><br /></p>
<h3 id="improve-download-in-edge">Improved downloading files in Edge on Windows</h3>
<p>When downloading a file in Edge browser, Selenide tracks temporary files “<em>.crdownload”. They are created by Chromium
engine during the download process.
Recently we realized that on Windows, Edge also creates temporary files “</em>.tmp”. Now Selenide tracks them too.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2167">PR 2167</a>.</p>
<p><br /></p>
<h3 id="update-dependencies">Updated dependencies</h3>
<ul>
<li>bump Selenium from 4.8.0 to 4.8.1, see <a href="https://github.com/selenide/selenide/pull/2161">PR 2161</a> and <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">Selenium release notes</a>.</li>
<li>Bump nettyVersion from 4.1.87.Final to 4.1.89.Final, see <a href="https://github.com/selenide/selenide/pull/2158">PR 2158</a>.</li>
</ul>
<p><br /></p>
<h3 id="rename-master-to-main">Renamed <code class="language-plaintext highlighter-rouge">master</code> branch to <code class="language-plaintext highlighter-rouge">main</code></h3>
<p>Yes, these are echoes of that same BLM. One smart person convinced me that it’s worth to rename the branch. :)</p>
<p><br /></p>
<h3 id="news">News</h3>
<ul>
<li>Post <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>Post <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>My video from Continuous Testing Meetup: <a href="https://www.youtube.com/watch?v=5qiuRoUcICs&t=48m02s">Selenide UI tests in java</a>, 23.01.2023</li>
</ul>
<p><br />
Well, why did I call this day <em>festive</em>?
It’s because February, 24 is actually the Independence Day of Estonia.
105 years ago, Estonian troops expelled the invaders from the country and proclaimed a new independent state.</p>
<center>
<img src="/images/2023/02/independence-day-estonia.png" width="300" />
</center>
<blockquote>
<p>Without that brave guys on the armored train, there would be no Selenide now. :)</p>
</blockquote>
<p><br /></p>
<h1 id="upd-released-selenide-6121">UPD Released Selenide 6.12.1</h1>
<p>Fixed an old bug in method <code class="language-plaintext highlighter-rouge">using</code>.</p>
<p>See <a href="https://github.com/selenide/selenide/milestone/176?closed=1">changelog</a></p>
<p><br /></p>
<h1 id="upd-released-selenide-6122">UPD Released Selenide 6.12.2</h1>
<p>Added a quick workaround for Chromedriver 111 issue:<br />
<code class="language-plaintext highlighter-rouge">Invalid Status code=403 text=Forbidden</code>.</p>
<p>See <a href="https://github.com/selenide/selenide/milestone/178?closed=1">changelog</a></p>
<p><br /></p>
<h1 id="upd-released-selenide-6123">UPD Released Selenide 6.12.3</h1>
<p>We fixed one old bug in method <code class="language-plaintext highlighter-rouge">$.download(FOLDER)</code> (if it’s called after <code class="language-plaintext highlighter-rouge">using</code>).</p>
<p>See <a href="https://github.com/selenide/selenide/milestone/179?closed=1">changelog</a></p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.11.12023-01-20T00:00:00+00:00https://selenide.org/2023/01/20/selenide-6.11.1
<p>Good jan!</p>
<p>We release a minor update <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">Truncate only WebDriverException</a></li>
<li><a href="#fix-download-to-folder">Tuned $.download(FOLDER)</a></li>
<li><a href="#update-dependencies">Updated dependencies</a></li>
<li><a href="#statistics">Statistics</a></li>
</ul>
<h3 id="truncate-webdriver-exception-message">Truncate only <code class="language-plaintext highlighter-rouge">WebDriverException</code> messages</h3>
<p>In a very rare situation - if you</p>
<ul>
<li>declare a custom command,</li>
<li>throw some assertion error from it,</li>
<li>and this error has multi-line message,</li>
</ul>
<p>then Selenide truncates this error message, leaving only the first line.</p>
<p>Initially, our intention was only to truncate error message of <code class="language-plaintext highlighter-rouge">WebDriverException</code> because it contains multiline garbage:</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>But here the mistake comes: Selenide truncated message not only for <code class="language-plaintext highlighter-rouge">WebDriverException</code>, but for all errors.
Now we fixed it, and you will see your multiline goodness entirely.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/2131">PR 2131</a>.</p>
<p><br /></p>
<h3 id="fix-download-to-folder">Fixed <code class="language-plaintext highlighter-rouge">$.download(FOLDER)</code> a bit</h3>
<p>This is a very rare case, so you probably didn’t even notice it.</p>
<p>But our tests flaked sometimes, so I had to start investigation. And found couple of rare bugs in <code class="language-plaintext highlighter-rouge">$.download(FOLDER)</code>.
Sometimes it could report that the file is not downloaded (though it was) in two cases:</p>
<ul>
<li>
<p><a href="https://github.com/selenide/selenide/pull/2116">#2116</a> If the file’s modification timestamp appeared in the previous second of click
(it may happen because different file systems may return file modification time with error up to 1 second. And it can be even in the past.)</p>
</li>
<li>
<p><a href="https://github.com/selenide/selenide/pull/2119">#2119</a> If the file’s modification timestamp was “0”
(according to the spec, it may happen if for some reason file system decided that the path is invalid)</p>
</li>
</ul>
<p>Now it should continue downloading in both cases.</p>
<p><br /></p>
<h3 id="update-dependencies">Updated 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, see <a href="https://github.com/selenide/selenide/pull/2126">PR 2126</a>.</li>
</ul>
<p><br /></p>
<h3 id="news">News</h3>
<ul>
<li>Post by Amuthan Sakthivel <a href="https://creatingvalue.substack.com/p/why-we-chose-selenide-over-selenium">Why we chose Selenide over Selenium for our Test Automation Needs</a></li>
</ul>
<p><br /></p>
<h3 id="statistics">Statistics</h3>
<p>Number of monthly downloads of Selenide exceeded 490 thousands!</p>
<center>
<img src="/images/2023/01/selenide.downloads.png" width="800" />
</center>
<p>To be continued…</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.11.02023-01-03T00:00:00+00:00https://selenide.org/2023/01/03/selenide-6.11.0
<center>
<img src="/images/2023/01/selenide-6.11.0.png" width="700" />
</center>
<p><br /></p>
<h1 id="happy-new-year-dear-friends">Happy New Year, dear friends!</h1>
<p>Santa Claus brought us a new release <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">Copy-paste methods</a></li>
<li><a href="#fix-download-with-credentials">Download file behind BasicAuth</a></li>
<li><a href="#download-large-files-via-proxy">Download large files via proxy</a></li>
<li><a href="#can-handle-unexpected-alerts">Unexpected alerts</a></li>
<li><a href="#fix-screenshot-file-permission">Screenshot file permissions</a></li>
<li><a href="#support-as-annotation">Annotation @As for fields without @FindBy</a></li>
<li><a href="#last-page-source">Last page source</a></li>
<li><a href="#page-url-in-error-message">Page URL in error message</a></li>
</ul>
<h3 id="added-copy-paste-methods">Added methods to copy and paste text</h3>
<p>We added two methods:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">Selenide.copy()</code> for copying currently selected text to clipboard, and</li>
<li><code class="language-plaintext highlighter-rouge">$.paste()</code> to paste clipboard content into input field.</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">"Life is highly overrated"</span><span class="o">));</span>
</code></pre></div></div>
<p>Known restrictions: these methods need a graphics environment. So they would not work on server linux.
But simple running <code class="language-plaintext highlighter-rouge">xvfb</code> should help.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1817">issue 1817</a>.<br />
Thanks to <a href="https://github.com/evpl">Evgenii Plugatar</a> for <a href="https://github.com/selenide/selenide/pull/2027">PR 2027</a>.</p>
<p><br /></p>
<h3 id="fix-download-with-credentials">Fixed method <code class="language-plaintext highlighter-rouge">Selenide.download(url)</code></h3>
<p>…in case if url contains login/password (the resource is protected by BasicAuth).</p>
<p>For example, this code worked few weeks ago, but stopped working after upgrading Apache Http client (internally used by Selenide):</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>In the latest update, Apache Http client enforced URL validation, and this part with login/password is not allowed anymore
(it’s kinda unsafe deprecated way of passing credentials).</p>
<p>Now Selenide removes credentials from url and sends them with http header <code class="language-plaintext highlighter-rouge">Authorization</code>.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2037">issue 2037</a>
and <a href="https://github.com/selenide/selenide/pull/2102">PR 2102</a>.</p>
<p><br /></p>
<h3 id="download-large-files-via-proxy">Now Selenide allows downloading large files via proxy</h3>
<p>If you use <code class="language-plaintext highlighter-rouge">PROXY</code> method for downloading files, you might know that file size could not exceed 64 megabytes.<br />
Initially, it seemed a reasonable limit: why should anyone need to load a test bench by downloading giant files?
(even 64 mb was quite big: BrowserUpProxy by default sets limit to 2 megabytes; we increased it to 64 in Selenide)</p>
<p>But it turned out that sometimes people want to test downloading large files.
After a discussion, we decided to simply remove this limit. You decide if you want to load your test environment.</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. Be aware that proxy might not quickly download files that are too large.
And BrowserUpProxy still has built-in technical restriction of 2 gigabytes (because of Integer type used for file size limit).</p>
<p>But at least now you can download, say, 200 megabyte files.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2082">issue 2082</a>
and <a href="https://github.com/selenide/selenide/pull/2098">PR 2098</a>.</p>
<p><br /></p>
<h3 id="can-handle-unexpected-alerts">Now you can handle unexpected alerts</h3>
<p>By default, Selenide ignores unexpected alerts in browser.
(More specifically, Selenide runs webdriver with option <code class="language-plaintext highlighter-rouge">capabilities.setCapability(UNHANDLED_PROMPT_BEHAVIOUR, ACCEPT)</code>).</p>
<p>On the one hand, this is convenient so that tests do not break due to sudden pop-up ads and other useless messages.
On the other hand, sometimes these alerts can contain useful information - in particular, a valuable error message.</p>
<p>If this is your case, now you can override this option:</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>Then you will get an exception saying what message that alert contained:</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">Oops</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="nl">Oops:</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">Oops</span><span class="o">}</span> <span class="c1">// edge</span>
<span class="nl">UnhandledAlertException:</span> <span class="o">:</span> <span class="nc">Oops</span> <span class="c1">// safari</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/2054">issue 2054</a>
and <a href="https://github.com/selenide/selenide/pull/2095">PR 2095</a>.</p>
<p><br /></p>
<h3 id="fix-screenshot-file-permission">Fixed permissions for screenshot file</h3>
<p>When your test fails, Selenide automatically takes a snapshot of current page, thus creating two files: : <code class="language-plaintext highlighter-rouge">*.png</code> and <code class="language-plaintext highlighter-rouge">*.html</code>.
It turned out that these files had different permissions:</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>And it caused difficulties for some advanced devops how wanted to run different step of build pipeline by different users.
<em>Whatever devops amuses… :)</em></p>
<p>Now both files have the same permissions: <code class="language-plaintext highlighter-rouge">-rw-r--r--</code>.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2081">issue 2081</a>
and <a href="https://github.com/selenide/selenide/pull/2084">PR 2084</a>.</p>
<p><br /></p>
<h3 id="support-as-annotation">Support <code class="language-plaintext highlighter-rouge">@As</code> annotation for fields without <code class="language-plaintext highlighter-rouge">@FindBy</code></h3>
<p>In Selenide, you can give readable names (aka “aliases”) for page object fields with method <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>But there was an idea that it would be convenient to put the name at the beginning of the line.
Otherwise, it would be visually lost on the right of the long selector.</p>
<p>Now you can give alias with annotation <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>But of course, the annotation will work only if you initialize the page object with method <code class="language-plaintext highlighter-rouge">Selenide.page()</code> or <code class="language-plaintext highlighter-rouge">Selenide.open()</code>.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2087">issue 2087</a>
and <a href="https://github.com/selenide/selenide/pull/2088">PR 2088</a>.</p>
<p><br /></p>
<h3 id="last-page-source">Added methods to get last saved page source</h3>
<p>It’s rarely needed, so don’t bother. Essentially, we added few methods to class <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>Thanks to <a href="https://github.com/armanayvazyan">Arman Ayvazyan</a> for <a href="https://github.com/selenide/selenide/pull/2065">PR 2065</a>.</p>
<p><br /></p>
<h3 id="page-url-in-error-message">Now you can add page URL to error message</h3>
<p>Sometimes it might be useful, sometimes harmful.
After a discussion, we decided to make this feature optional (in a form of a plugin).</p>
<p>Let it stay in experimental status for now.
We will probably play with error message formats in the future.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/980">issue 980</a> and <a href="https://github.com/selenide/selenide/pull/2097">PR 2097</a>.</p>
<p><br /></p>
<h3 id="year-summary">Year summary</h3>
<p>Let’s sum up year 2022? During this year, Selenide was mentioned in several ratings:</p>
<ul>
<li><a href="https://qameta.io/blog/5-testing-automation-tools/">5 Testing Automation Tools</a> in Qameta Software blog</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>and finally,</p>
<ul>
<li>Selenide got mentioned on <a href="https://www.selenium.dev/ecosystem/">Selenium official site</a> in category “Ecosystem”.</li>
</ul>
<p>Selenide monthly downloads statistics <strong>grew by half</strong>:</p>
<blockquote>
<p>from 302 thousands in January<br />
to 469 thousands in November.</p>
</blockquote>
<h3 id="new-year-wishes">And still</h3>
<p>It’s been a terrible year.</p>
<p>I hope that in the coming year the war will end, the guilty will be punished, the citizens of the oppressed countries will finally overthrow their tyrants.</p>
<p>And the beautiful free country of Ukraine will be rebuilt and will bloom more than ever.</p>
<blockquote>
<p>And after a year, we will see you in Kyiv at the wonderful <a href="https://seleniumcamp.com/">SeleniumCamp conference</a>.</p>
</blockquote>
<p>Glory to the heroes!</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.10.22022-12-08T00:00:00+00:00https://selenide.org/2022/12/08/selenide-6.10.2
<p><br /></p>
<h1 id="good-evening">Good evening!</h1>
<p>We got mini-release <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">Added method $.press()</a></li>
<li><a href="#trigger-change-events-by-select-methods">Trigger change event in $.select*</a></li>
<li><a href="#friendly-select-option-in-reports">selectOption in reports</a></li>
<li><a href="#friendly-local-storage-in-reports">localStorage in reports</a></li>
<li><a href="#news">News</a></li>
</ul>
<h3 id="added-method-press">Added method <code class="language-plaintext highlighter-rouge">$.press()</code></h3>
<p>It’s essentially the same ss <code class="language-plaintext highlighter-rouge">sendKeys()</code>, but it’s not <code class="language-plaintext highlighter-rouge">void</code>. You can <em>chain</em> it with other methods:</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>Thanks to <a href="https://github.com/amuthansakthivel">Amuthan Sakthivel</a> for <a href="https://github.com/selenide/selenide/pull/2032">PR 2032</a>.</p>
<p><br /></p>
<h3 id="trigger-change-events-by-select-methods">Trigger <code class="language-plaintext highlighter-rouge">change</code> event by method <code class="language-plaintext highlighter-rouge">$.select*</code></h3>
<p>As you remember, in previous release we <a href="/2022/11/21/selenide-6.10.0/#select-options-using-javascript">reworked working with selects using JavaScript</a>.
But we forgot to trigger <code class="language-plaintext highlighter-rouge">focus</code>, <code class="language-plaintext highlighter-rouge">click</code> and <code class="language-plaintext highlighter-rouge">change</code> events. Now we trigger them.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/2050">issue 2050</a>.
Thanks to <a href="https://github.com/cocorossello">Vicente Rossello Jaume</a> for <a href="https://github.com/selenide/selenide/pull/2051">PR 2051</a>.</p>
<p>UPD. Fixed once again in <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">Show <code class="language-plaintext highlighter-rouge">$.selectOption()</code> friendly in reports</h3>
<p>Another minor issue caused by the refactoring of selects: these operations look ugly in reports.<br />
That’s because Java arrays don’t have standard method <code class="language-plaintext highlighter-rouge">toString()</code>, and developers have to re-invent the wheel.</p>
<p>Before:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>| #blockChannel | select option([TV Rain, [Ljava.lang.String;@6732726]) | PASS | 487 |
</code></pre></div></div>
<p>After:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>| #blockChannel | select option(TV Rain) | PASS | 487 |
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/2047">issue 2047</a> and <a href="https://github.com/selenide/selenide/pull/2052">PR 2052</a>.</p>
<p><br /></p>
<h3 id="friendly-local-storage-in-reports">Show <code class="language-plaintext highlighter-rouge">localStorage</code> friendly in reports</h3>
<p>Similar problem with <code class="language-plaintext highlighter-rouge">sessionStorage</code> and <code class="language-plaintext highlighter-rouge">localStorage</code>: they look unreadable in reports.</p>
<p>Before:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>| com.codeborne.selenide.LocalStorage@138a952f | set item(['Bout', 9125]) |
| com.codeborne.selenide.SessionStorage@549w123gg | set item(['Griner', 3285]) |
</code></pre></div></div>
<p>After:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>| localStorage | set item(['Bout', 9125]) |
| sessionStorage | set item(['Griner', 3285]) |
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/2045">issue 2045</a> and <a href="https://github.com/selenide/selenide/pull/2046">PR 2046</a>.</p>
<p><br /></p>
<h3 id="update-dependencies">Upgraded 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="subprojects">Subprojects</h3>
<p>We also released our subprojects:</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">News</h3>
<ul>
<li>Selenide Tutorial: <a href="https://www.youtube.com/watch?v=5vrYMfsxkGY&list=PL9ok7C7Yn9A9YyRISFrxHdaxb5qqrxp_i&index=4&ab_channel=TestingMiniBytes">Replacement for Selenium?</a> on Testing Mini Bytes channel</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> by Oleksandr Podoliako</li>
</ul>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.10.02022-11-21T00:00:00+00:00https://selenide.org/2022/11/21/selenide-6.10.0
<p><br /></p>
<h1 id="evil-evening">Evil evening!</h1>
<p>We released <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">Improved file download algorithm</a></li>
<li><a href="#fail-download-early">Fail download early</a></li>
<li><a href="#select-options-using-javascript">Select options using JavaScript</a></li>
<li><a href="#make-click-chainable">Made click chainable</a></li>
<li><a href="#fix-size-for-new-tabs">Fixed size of new tabs</a></li>
<li><a href="#encode-basic-auth-credentials-in-url">BasicAuth with special characters</a></li>
<li><a href="#news">News</a></li>
</ul>
<h3 id="slow-download-in-firefox">Improved file download algorithm</h3>
<p>Selenide contains several algorithms for downloading files: <code class="language-plaintext highlighter-rouge">HTTPGET</code>, <code class="language-plaintext highlighter-rouge">PROXY</code> and <code class="language-plaintext highlighter-rouge">FOLDER</code>.
Let’s talk about <code class="language-plaintext highlighter-rouge">FOLDER</code>.
To download a file, it clicks the button and waits for new files in downloads folder.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">File</span> <span class="n">racoons</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">racoons</span><span class="o">).</span><span class="na">hasName</span><span class="o">(</span><span class="s">"racoons.xls"</span><span class="o">);</span>
</code></pre></div></div>
<p>The problem is that it didn’t work well in Firefox in case of very slow download.
We realized that Firefox creates immediately two files: “racoons.xls” and “racoons.xls.part” - both are empty.
And only then starts filling “racoons.xls.part”.</p>
<p><br />
Now the <code class="language-plaintext highlighter-rouge">FOLDER</code> algorithm is smarter. It</p>
<ol>
<li>waits until some suitable file appears in the downloads folder;</li>
<li>waits until all <code class="language-plaintext highlighter-rouge">*part</code> files disappear (in Firefox);</li>
<li>waits until all <code class="language-plaintext highlighter-rouge">*crdownload</code> (in Chrome);</li>
<li>waits until none of files has been modified for 1+ seconds (in other browsers).</li>
</ol>
<p>This approach should provide more reliable file downloads.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1989">issue 1989</a> and <a href="https://github.com/selenide/selenide/pull/2003">PR 2003</a>.</p>
<p><br /></p>
<h3 id="fail-download-early">Fail fast the downloading process if no progress observed</h3>
<p>People often set a long timeout for downloading files. Especially when downloading a large file:</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">"puten mobshiza.MP4"</span><span class="o">));</span>
</code></pre></div></div>
<p>But it doesn’t make sense so long if the downloading process has not even started.
For example, if the click missed the button (how it can happen, I showed in video <a href="https://www.youtube.com/watch?v=-c5XT2v5gRY&ab_channel=DEVCLUB.EE&t=37m31s">“Flaky tests”</a>).</p>
<p>To fail earlier, you can set another parameter “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">"puten mobshiza.MP4"</span><span class="o">));</span>
</code></pre></div></div>
<p>In this case, the general download timeout is 99 seconds, BUT it during 2 seconds none of files is modified, then the
method will throw an exception immediately.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1990">issue 1990</a> and <a href="https://github.com/selenide/selenide/pull/2023">PR 2023</a>.</p>
<p><br /></p>
<h3 id="select-options-using-javascript">Select <code class="language-plaintext highlighter-rouge"><select></code> options using JavaScript</h3>
<p>It should made work with <code class="language-plaintext highlighter-rouge"><select></code>s faster. As a bonus, now Selenide throws a more detailed exception if <code class="language-plaintext highlighter-rouge"><select></code> (or <code class="language-plaintext highlighter-rouge"><option></code>) was <code class="language-plaintext highlighter-rouge">disabled</code>.</p>
<p>Given a <code class="language-plaintext highlighter-rouge"><select></code> with some disabled options:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><select</span> <span class="na">id=</span><span class="s">"region"</span><span class="nt">></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"belgorod"</span><span class="nt">></span>Belgorod<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"kherson"</span> <span class="na">disabled</span><span class="nt">></span>Kherson<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"zaporozhia"</span> <span class="na">disabled</span><span class="nt">></span>Zaporozhia<span class="nt"></option></span>
<span class="nt"></select></span>
</code></pre></div></div>
<p>Trying to select a <code class="language-plaintext highlighter-rouge">disabled</code> option:</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>will throw a clear error message:</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>Before this release, the error was not so detailed:</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>(and even earlier, such a test did not fall at all, but did not select the option either)</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1553">issue 1553</a> and <a href="https://github.com/selenide/selenide/pull/1876">PR 1876</a>.</p>
<blockquote>
<p>Specials thanks to <a href="https://github.com/bereg2k">Oleg Berezhnoy</a> for <a href="https://github.com/selenide/selenide/pull/1553">PR 1553</a>.
Though it was not merged, it triggered a discussion in Selenide and even in Selenium team: what is a “just framework”
and “opinionated framework”.</p>
</blockquote>
<p><br /></p>
<h3 id="make-click-chainable">Made <code class="language-plaintext highlighter-rouge">$.click(options)</code> chainable</h3>
<p>People often complain that method <code class="language-plaintext highlighter-rouge">$.click()</code> has return type <code class="language-plaintext highlighter-rouge">void</code>. You cannot chain it like this:</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>Alas, we cannot fix it, since class <code class="language-plaintext highlighter-rouge">SelenideElement</code> inherits method <code class="language-plaintext highlighter-rouge">void click()</code> from Selenium’s <code class="language-plaintext highlighter-rouge">WebElement</code>.</p>
<p>But we made chainable another (overloaded) <code class="language-plaintext highlighter-rouge">click</code> method (the one with parameters).<br />
At least this one can now be chained:</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>See <a href="https://github.com/selenide/selenide/issues/2007">issue 2007</a> and <a href="https://github.com/selenide/selenide/pull/2008">PR 2008</a>.</p>
<p><br /></p>
<h3 id="fix-size-for-new-tabs">Fixed window size of new tabs</h3>
<p>Thanks to <a href="https://github.com/BorisOsipov">Boris Osipov</a> for <a href="https://github.com/selenide/selenide/pull/2017">PR 2017</a>.</p>
<p>P.S. Fixed once again in <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">Support BasicAuth login/password with special characters</h3>
<p>Selenide can open sites protected by 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>This login/password is added either to http header <code class="language-plaintext highlighter-rouge">Authorization</code> (if proxy is enabled) or URL (if proxy is disabled).</p>
<p>Recently I discovered that the the second way doesn’t work correctly if login or password contains special characters.
When adding to URL, these characters were not escaped, causing an invalid 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>browser could not open such a link.</p>
<blockquote>
<p>I am curious, why nobody every complained about that? Do you all use just <code class="language-plaintext highlighter-rouge">scott</code>/<code class="language-plaintext highlighter-rouge">tiger</code> credentials? :)</p>
</blockquote>
<p>Now Selenide encodes such characters and generates a valid 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>See <a href="https://github.com/selenide/selenide/issues/2020">issue 2020</a> and <a href="https://github.com/selenide/selenide/pull/2021">PR 2021</a>.</p>
<p><br /></p>
<h3 id="update-dependencies">Upgraded dependencies</h3>
<ul>
<li>Selenium from 4.5.0 to 4.6.0, see <a href="https://www.selenium.dev/blog/2022/selenium-4-6-0-released/">changelog</a></li>
<li>WebDriverManager from 5.3.0 to 5.3.1, see <a href="https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md#531---2022-11-04">changelog</a></li>
<li>BrowserUpProxy from 2.2.3 to 2.2.5, see <a href="https://github.com/valfirst/browserup-proxy/blob/master/CHANGELOG.md">changelog</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, see <a href="https://github.com/LittleProxy/LittleProxy/milestone/19?closed=1">changelog</a></li>
<li>#2014 Bump httpclient5 from 5.1.3 to 5.2, see <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, see <a href="https://github.com/selenide/selenide/pull/2025">PR 2025</a></li>
</ul>
<p><br /></p>
<h3 id="child-projects">Child projects</h3>
<p>We also released our child projects:</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">News</h3>
<ul>
<li>JetBrains released AQUA - new <a href="https://www.jetbrains.com/aqua/">IDE for automated tests</a>! Nice logo!</li>
<li>Selenium introduced its own built-in <a href="https://www.selenium.dev/blog/2022/introducing-selenium-manager/">WebDriverManager analogue</a>. Someone already tried it?</li>
<li>New framework <a href="https://gitlab.com/brewcode/selenide-pages">Selenide Pages</a> based on Selenide from Maxim Kochetkov. Nice logo!</li>
</ul>
<h3 id="videos">Videos and posts</h3>
<ul>
<li>Post <a href="https://www.linkedin.com/pulse/all-selenide-muhammad-naeem/">All About Selenide</a> by Muhammad Naeem</li>
<li>Video <a href="https://morioh.com/p/018678871de9">Working with web elements using Selenide</a> by Automation Bro</li>
<li>Post <a href="https://dev.to/automationbro/page-object-model-selenide-tutorial-series-g3g">Page Object Model</a> from “Selenide Tutorial Series” by Automation Bro</li>
</ul>
<p><br /></p>
<h3 id="statistics">Statistics</h3>
<ul>
<li>Our <a href="https://www.linkedin.com/groups/9154550/">Selenide user group in LinkedIn</a> has already 176 members. Join!</li>
<li>We got a fresh downloads statistics for October. We passed the 470 thousands line!</li>
</ul>
<center>
<img src="/images/2022/11/selenide.downloads.png" width="800" />
</center>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.9.02022-10-07T00:00:00+00:00https://selenide.org/2022/10/07/selenide-6.9.0
<p><br /></p>
<h1 id="yo-seleniders">Yo Seleniders!</h1>
<p>Let me break your doomscrolling with some good news.</p>
<p>We released <a href="https://github.com/selenide/selenide/milestone/166?closed=1">Selenide 6.9.0</a>!
Basically, they pumped proxies and updated selenium.</p>
<ul class="blogpost-menu">
<li><a href="#proxy-mock-response">Fake server response in proxy</a></li>
<li><a href="#secure-authorization-header">Authorization header</a></li>
<li><a href="#resolve-proxy-hostname">Improve proxy host name</a></li>
<li><a href="#upgrade-to-selenium-4.5.0">Upgrade to Selenium 4.5.0</a></li>
<li><a href="#remove-opera-support">Drop Opera support</a></li>
<li><a href="#news">News</a></li>
</ul>
<h3 id="proxy-mock-response">Now Selenide proxy can mock server response</h3>
<p>As you know, Selenide can run its own embedded proxy server. It listens requests between browser and other world.
We mostly used it in read-only mode (logging, downloading files). But now you can also change the traffic.
Namely, you can replace server response. It may be useful to mock the response of some service.</p>
<p>Let’s look at some simple abstract example.</p>
<h4 id="example">Example</h4>
<p>Let’s say you’re testing a site showing the results of a referendum.
It’s a html page on address, say, https://referendum.ru, which calls service https://cik.ru to fetch json with voting results.</p>
<p>Since the results are not known in advance, but the site needs to be tested here and now, we want to check how it will
look in different corner cases.</p>
<h4 id="test">Test</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">-></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">"not only satisfy but also surprised"</span><span class="o">));</span>
</code></pre></div></div>
<h4 id="explanation">Explanation</h4>
<p>Look at the first parameter <code class="language-plaintext highlighter-rouge">cik-mock</code>. This is <em>name</em> of the mock.<br />
You can use it later to cancel the mock (to avoid occasional effects on the following tests):</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>Or you can just cancel all the mocks for safety:</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="constraints">Constraints</h4>
<p>If you site and mocked service run on same domain, there is no constraints.<br />
But if the site calls a service on another domain, mock will work only if</p>
<ul>
<li>both site and mock run on https (not http)</li>
<li>service is alive and accessible from proxy</li>
</ul>
<h4 id="in-sum">In sum</h4>
<p>Using mocks is a powerful technique letting us verify different corner cases that are hard or even impossible to reproduce otherwise <br />
(“146% votes for”, “no one showed up to vote”, “service is unavailable” etc.)</p>
<blockquote>
<p>Do not be shy about your desire to correct, clean up, add something.
It will work as you want.</p>
</blockquote>
<p>See <a href="https://github.com/selenide/selenide/issues/1254">issue 1254</a> and <a href="https://github.com/selenide/selenide/pull/1978">PR 1978</a>.</p>
<p><br /></p>
<h3 id="secure-authorization-header">Send authorization header only to specified domain</h3>
<p>Some site you need to test are protected by BasicAuth.
Selenide allows to open such sites with overloaded method <code class="language-plaintext highlighter-rouge">open</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">"saver-of-the-world"</span><span class="o">,</span> <span class="s">"gojda!!!"</span><span class="o">));</span>
</code></pre></div></div>
<p>This method can overcome BasicAuth:</p>
<ul>
<li>if proxy is not enabled - by adding login/password to URL,</li>
<li>and if proxy is enabled - by adding http header <code class="language-plaintext highlighter-rouge">Authorization</code> to requests from browser to server.</li>
</ul>
<p>But here’s the problem. Recently we realized that Selenide sent <code class="language-plaintext highlighter-rouge">Authorization</code> header not only to the app under test,
but also to all other services (e.g. S3 or Google authentication).</p>
<p>Now Selenide will send <code class="language-plaintext highlighter-rouge">Authorization</code> only to needed domain. But you will also need to specify the domain in constructor:</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">"saver-of-the-world"</span><span class="o">,</span> <span class="s">"gojda!!!"</span><span class="o">));</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/1974">issue 1974</a> and <a href="https://github.com/selenide/selenide/pull/1975">PR 1975</a>.</p>
<p><br /></p>
<h3 id="resolve-proxy-hostname">Improved resolving proxy host name</h3>
<p>When you enable proxy in Selenide (e.g. by setting <code class="language-plaintext highlighter-rouge">Configuration.proxyEnabled = true</code>),
it will run embedded proxy server on random port. And open a browser with instructions to use proxy <code class="language-plaintext highlighter-rouge">HOST:PORT</code>.
The question is, which HOST to use?</p>
<p>Until now, we used expression <code class="language-plaintext highlighter-rouge">ClientUtil.getConnectableAddress()</code> to resolve the host name (it’s default behaviour of BrowserUpProxy).
But from this release, we will use <code class="language-plaintext highlighter-rouge">new NetworkUtils().getNonLoopbackAddressOfThisMachine()</code> (it’s Selenium internal method).
I’m too lazy to figure out what their specifics are, but they may return different results on my machine:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">new NetworkUtils().getNonLoopbackAddressOfThisMachine()</code> -> <code class="language-plaintext highlighter-rouge">192.168.0.18</code></li>
<li><code class="language-plaintext highlighter-rouge">ClientUtil.getConnectableAddress()</code> -> <code class="language-plaintext highlighter-rouge">127.0.0.1</code></li>
</ul>
<p>The first one is definitely better when the browser runs on different machine or in a container.
The proxy will just not be accessible by address <code class="language-plaintext highlighter-rouge">127.0.0.1</code> from other machine.</p>
<blockquote>
<p>If none expression works properly for you, you can always specify host name explicitly by setting
<code class="language-plaintext highlighter-rouge">Configuration.proxyHost = "my.comp.eu";</code></p>
</blockquote>
<p>See <a href="https://github.com/selenide/selenide/pull/1970">PR 1970</a>.</p>
<p><br /></p>
<h3 id="upgrade-to-selenium-4.5.0">Upgraded to Selenium 4.5.0</h3>
<p>Notable changes:</p>
<ul>
<li>dropped support for Opera browser</li>
<li>added alternative implementation of webdriver transport using JDK 11 HTTP client instead of Netty client</li>
<li>added checks for <code class="language-plaintext highlighter-rouge">disabled</code> in class <code class="language-plaintext highlighter-rouge">Select</code> (now you cannot select a disabled options anymore)</li>
<li>removed host name from Selenium exceptions
<blockquote>
<p>arrr, I asked for this change <a href="https://github.com/SeleniumHQ/selenium/issues/489">since 2015</a>!!!</p>
</blockquote>
</li>
</ul>
<p>See <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">changelog</a> and
<a href="https://github.com/selenide/selenide/pull/1967">PR 1967</a>.</p>
<p><br /></p>
<h3 id="remove-opera-support">Removed support for Opera browser</h3>
<p>As a consequence of the Selenium upgrade, we also had to drop Opera support. I guess the reason is that Opera uses
Chrome engine and is not very different from Chrome. If you still need to run tests in Opera - it’s possible, just
use chromedriver.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/1967">PR 1967</a>.</p>
<p><br /></p>
<h3 id="do-not-log-get-alias">Removed <code class="language-plaintext highlighter-rouge">getAlias</code> from reports</h3>
<p>Thanks to <a href="https://github.com/reserved-word">Reserved Word</a> for <a href="https://github.com/selenide/selenide/pull/1971">PR 1971</a>.</p>
<p><br /></p>
<h3 id="restore-setting-connection-timeout">Restored setting “connection timeout”</h3>
<p>Few people need this, so feel free to skip it.</p>
<p class="small">We used to have two settings for the webdriver http client: “connection timeout” and “read timeout”.
The first one had to be removed when upgrading to Selenium 4, because it was cut out there.
Now it was resuscitated in Selenium 4.5.0, well, so we resuscitated also.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/1977">PR 1977</a>.</p>
<p><br /></p>
<h3 id="update-dependencies">Upgraded 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>
<p>Not only IT people suffer from <a href="https://www.youtube.com/watch?v=laIGavOMcw8&ab_channel=FoilArmsandHog">constantly changing requirements</a>!</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.8.12022-09-27T00:00:00+00:00https://selenide.org/2022/09/27/selenide-6.8.1
<p><br /></p>
<h1 id="gooda">Gooda!</h1>
<p>Catch min-bugfix <a href="https://github.com/selenide/selenide/milestone/165?closed=1">Selenide 6.8.1</a>.</p>
<p>This only applies to those who directly call in their tests</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>and encountered <code class="language-plaintext highlighter-rouge">NoClassDefFoundError</code> after upgrading to <a href="/2022/09/24/selenide-6.8.0/">Selenide 6.8.0</a>.</p>
<p><br /></p>
<h3 id="pre-history">Prehistory</h3>
<p>What is OpenTelemetry?
This is some kind of thing that was added to Selenium 4 for some reason, but nobody really knows why it’s needed
and how to use it. :) In fact, no one cares, no one uses it. :)</p>
<p>In Selenide, we also removed it in <a href="https://github.com/selenide/selenide/pull/1763">PR 1763</a>.</p>
<blockquote>
<p>OpenTelemetry dependency in Selenium is like Special Military Operation: nobody knows why it’s needed.</p>
</blockquote>
<h3 id="the-problem">The problem</h3>
<p>So, most Selenide users don’t have such a problem.</p>
<p>BUT
you might into trouble if you call constructor <code class="language-plaintext highlighter-rouge">new RemoteWebDriver(url, options)</code> in your tests.
Unfortunately, it requires OpenTelemetry dependency. And after upgrading to <a href="/2022/09/24/selenide-6.8.0/">Selenide 6.8.0</a>
these users might get <code class="language-plaintext highlighter-rouge">NoClassDefFoundError</code>.</p>
<p><br /></p>
<h3 id="temporary-solution">Temporary solution</h3>
<p>Add parameter <code class="language-plaintext highlighter-rouge">false</code> to the constructor: <code class="language-plaintext highlighter-rouge">new RemoteWebDriver(url, options, false)</code>.
This <code class="language-plaintext highlighter-rouge">false</code> says “please don’t user telemetry”.</p>
<p><br /></p>
<h3 id="restored-opentelemetry">Demobilized OpenTelemetry dependency</h3>
<p>In short, we quickly released Selenide 6.8.1, which brought back OpenTelemetry.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1965">issue 1965</a> and <a href="https://github.com/selenide/selenide/pull/1966">PR 1966</a>.</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.8.02022-09-24T00:00:00+00:00https://selenide.org/2022/09/24/selenide-6.8.0
<p><br /></p>
<h1 id="bad-morning">Bad morning!</h1>
<p>While the world is going crazy, we are releasing <a href="https://github.com/selenide/selenide/milestone/161?closed=1">Selenide 6.8.0</a>.<br />
Not so many features, rather dependency updates.</p>
<ul class="blogpost-menu">
<li><a href="#deep-shadow-selectors">Recursive search in shadow dom</a></li>
<li><a href="#add-page-without-class">Method page() without parameters</a></li>
<li><a href="#as-annotation">Annotation @As</a></li>
<li><a href="#news">News</a></li>
</ul>
<h3 id="deep-shadow-selectors">Recursive search in shadow dom</h3>
<p>As you probably know, Selenide has <a href="/2020/03/18/selenide-5.10.0">methods</a> to find elements inside shadow dom.
And even in multiple embedded shadow doms:</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>But you still need to waste time to investigate these doms and find proper locators for all those shadow roots.</p>
<p>Now you can save time with the help of new method <code class="language-plaintext highlighter-rouge">shadowDeepCss</code> - it searches the element recursively in all shadow roots all over the 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>Naturally, there is still a risk that such “too generic” search can find a wrong element which probably resides in
another shadow dom, but occasionally matches your locator.<br />
In this case you will need to return to the old good “exact” search.</p>
<blockquote>
<p>As in the case of databases and sausages, “it’s better not to look inside” - there is a bunch of tricky javascript for tree search.</p>
</blockquote>
<p>See <a href="https://github.com/selenide/selenide/issues/1946">issue 1946</a>.</p>
<p>Thanks to</p>
<ol>
<li><a href="https://github.com/BorisOsipov">Boris Osipov</a> for <a href="https://github.com/selenide/selenide/pull/1947">PR 1947</a>, and</li>
<li><a href="https://github.com/Georgegriff">Georgegriff</a> for
project <a href="https://github.com/Georgegriff/query-selector-shadow-dom">query-selector-shadow-dom</a>, from where we stole this code. :)</li>
</ol>
<p><br /></p>
<h3 id="add-page-without-class">Added method <code class="language-plaintext highlighter-rouge">page()</code> not requiring <code class="language-plaintext highlighter-rouge">Class</code> argument</h3>
<p>Dear Page Object fans, take a seat, this is for you. There is a turning point in your life.</p>
<p>Now you don’t need to pass <code class="language-plaintext highlighter-rouge">Class</code> argument to method <code class="language-plaintext highlighter-rouge">page(Class pageObjectClass)</code>. Wow!</p>
<p>Instead of</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>you can just write</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>I used to think Java couldn’t do that, but then I found <a href="https://twitter.com/tagir_valeev/status/1262763570904719361">a hack</a>.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/1961">PR 1961</a>,
and thanks to <a href="https://twitter.com/tagir_valeev">Tagir Valeev</a> for the hack.</p>
<p><br /></p>
<h3 id="as-annotation">Added annotation <code class="language-plaintext highlighter-rouge">@As</code></h3>
<p>… for giving human-readable aliases for page object fields.</p>
<h4 id="1-without-aliases">1. Without aliases</h4>
<p>Assuming you have a page object with <code class="language-plaintext highlighter-rouge">@FindBy</code> annotations:</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>and a test like <code class="language-plaintext highlighter-rouge">page.header.shouldBe(visible)</code>.</p>
<p>In reports, it looks quite long and unreadable:</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>And when the test fails, it’s quite hard to understand which element was not found:</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>People often want to give some human-readable names to elements to avoid seeing long ugly xpath’s in reports.</p>
<h4 id="2-resistance">2. Resistance</h4>
<p>I have always been against it.
I believe that not only reports, but also the tests themselves should be readable. I stand for clean code.
If you don’t like the ugly xpath - well, just change it, don’t hide it!</p>
<p>But still decided to meet people’s need.
In <a href="/2020/12/26/selenide-5.17.0/">Selenide 5.17.0</a>, we added method <code class="language-plaintext highlighter-rouge">$.as("alias")</code>.</p>
<h4 id="3-with-aliases">3. With aliases</h4>
<p>And in this release you can also add annotation <code class="language-plaintext highlighter-rouge">@As</code> to page object fields.</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>It will look readable in reports:</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>And when the test fails, it’s easier to understand which element was not found:</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>See <a href="https://github.com/selenide/selenide/issues/1903">issue 1903</a> and <a href="https://github.com/selenide/selenide/pull/1956">PR 1956</a>.</p>
<blockquote>
<p>Don’t forget: everyone lies.</p>
<p>Documentation lies, comments lie, users lie.
Sooner or later, the alias will also lie. Someone changed the locator, but forgot the alias.
Or the element was copied, but the alias was forgotten to be changed. Etc.</p>
<p>Reports are good, but in the end, only the code can be trusted.</p>
</blockquote>
<p><br /></p>
<h3 id="update-dependencies">Updated 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 – see <a href="https://junit.org/junit5/docs/5.9.1/release-notes/">release notes</a></li>
</ul>
<blockquote>
<p>Announced partial mobilization of dependencies!</p>
</blockquote>
<p><br /></p>
<h3 id="news">News</h3>
<ul>
<li>The series from Dilpreet Johal continues - now <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> by Tomasz Buga</li>
<li>Java 19 has been released.</li>
</ul>
<h3 id="statistics">Statistics</h3>
<p>Latest Selenide download statistics only makes us happy. We passed the 400 thousands line!</p>
<center>
<img src="/images/2022/09/selenide.downloads.png" width="800" />
</center>
<p><br /></p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.7.42022-09-05T00:00:00+00:00https://selenide.org/2022/09/05/selenide-6.7.4
<p><br /></p>
<h1 id="hey-there">Hey there!</h1>
<p><br />
We did yet another nano-release <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">Added setting <code class="language-plaintext highlighter-rouge">remoteReadTimeout</code></h3>
<p>I recently <a href="https://www.youtube.com/watch?v=-KGtZoFVzr8&list=PL9Z-JgiTsOYRfoG_mcRBlTUIFPIknhQ6S">complained about</a> too many settings in Selenide.</p>
<p>Nevertheless, we added yet another setting <code class="language-plaintext highlighter-rouge">Configuration.remoteReadTimeout</code> (a.k.a. <code class="language-plaintext highlighter-rouge">-Dselenide.remoteReadTimeout</code>).</p>
<p>It may be useful if you run browser on a remote server, but the number if browser is limited on that server, and
your tests need to wait in a queue for a free browser. In this case the default timeout for 1.5 minutes might not be
enough, and you need to increase the timeout.</p>
<blockquote>
<p>Personally, I call it HELL on the project, but who are we to stop people from voluntarily frying in a pan …</p>
</blockquote>
<p>Now you can set any timeout from build scripts, command line etc.</p>
<p>Thanks to <a href="https://github.com/rodion-goritskov">Rodion Goritskov</a> for <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">Fixed mini-bug in “Dead threads watchdog”</h3>
<p>Have you ever seen <code class="language-plaintext highlighter-rouge">java.lang.IllegalStateException: Shutdown in progress</code> in logs?</p>
<p>It means you hasn’t upgraded to <a href="/2022/08/14/selenide-6.7.2/">Selenide 6.7.2</a> :)</p>
<p>Now I recommend to upgrade to 6.7.4 - and you get fixed both memory leaks and IllegalStateException.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1942">issue 1942</a> and <a href="https://github.com/selenide/selenide/pull/1943">PR 1943</a>.</p>
<p><br /></p>
<h3 id="update-dependencies">Upgraded 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">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&list=PL6AdzyjjD5HC4NJuc083bzFq86JekmASF&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/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.7.32022-08-27T00:00:00+00:00https://selenide.org/2022/08/27/selenide-6.7.3
<p><br /></p>
<h1 id="good-saturday">Good saturday!</h1>
<p><br />
You are reading release notes for <a href="https://github.com/selenide/selenide/milestone/163?closed=1">Selenide 6.7.3</a>.</p>
<h3 id="condition-partial-value">Added condition <code class="language-plaintext highlighter-rouge">partialValue</code></h3>
<p>Similarly to <code class="language-plaintext highlighter-rouge">$.shouldHave(partialText("Good Co"))</code>, now you have <code class="language-plaintext highlighter-rouge">$.shouldHave(partialValue("Cola"))</code>.</p>
<p>It’s needed if you set <code class="language-plaintext highlighter-rouge">Configuration.textCheck = FULL_TEXT</code>, but need to check a value of some input or textarea <em>partially</em>.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1923">issue 1923</a> and <a href="https://github.com/selenide/selenide/pull/1924">PR 1924</a>.</p>
<p><br /></p>
<h3 id="condition-tag-name">Added condition <code class="language-plaintext highlighter-rouge">tagName</code></h3>
<p>You probably don’t need it often. Because we often find element by the tag, and only then verify some its attributes.</p>
<p>Anyway, now you can verify the tag name of an element:</p>
<p><code class="language-plaintext highlighter-rouge">$(".btn-primary").shouldHave(tagName("button"));</code></p>
<p>Or filter a collection by tag name:</p>
<p><code class="language-plaintext highlighter-rouge">$$(byText("Submit!")).filterBy(tagName("button"));</code></p>
<p>See <a href="https://github.com/selenide/selenide/issues/1928">issue 1928</a> and <a href="https://github.com/selenide/selenide/pull/1929">PR 1929</a>.</p>
<p><br /></p>
<h3 id="check-select-tag">Now we check that element is <code class="language-plaintext highlighter-rouge"><select></code></h3>
<p>… in methods <code class="language-plaintext highlighter-rouge">$.getSelectedText()</code> and <code class="language-plaintext highlighter-rouge">getSelectedValue()</code>.</p>
<p>The initial intention of these methods was to find a selected <code class="language-plaintext highlighter-rouge"><option></code> in a <code class="language-plaintext highlighter-rouge"><select></code> and return its text or value.</p>
<p>But</p>
<ol>
<li>it’s not obvious from the name (and that’s why we renamed methods to <code class="language-plaintext highlighter-rouge">$.getSelectedOptionText()</code> and <code class="language-plaintext highlighter-rouge">getSelectedOptionValue()</code>)</li>
<li>you could call these methods on any other element but <code class="language-plaintext highlighter-rouge"><select></code> - and get an unpredictable behavior.</li>
</ol>
<p>Now call to <code class="language-plaintext highlighter-rouge">$("div").getSelectedOptionText()</code> will throw <code class="language-plaintext highlighter-rouge">IllegalArgumentException</code>.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/1934">PR 1934</a>.</p>
<p><br /></p>
<h3 id="update-dependencies">Updated 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">News</h3>
<ul>
<li>Selenide puzzler <a href="/2022/08/22/selenide-puzzler/">Logical AND or OR?</a></li>
<li>Selenide got to <a href="https://aglowiditsolutions.com/blog/top-java-frameworks/">Top Java Frameworks to Use in 2022</a></li>
</ul>
<p>And finally, <strong>the main achievement</strong>:</p>
<ul>
<li>Selenide got mentioned on <a href="https://www.selenium.dev/ecosystem/">official Selenium site</a> in category “Ecosystem”!</li>
</ul>
<p>Impossible!</p>
<p>It hasn’t even been 10 years!</p>
<p>Wait, it’s been…</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Selenide puzzler2022-08-22T00:00:00+00:00https://selenide.org/2022/08/22/selenide-puzzler
<p><br /></p>
<h1 id="good-night">Good night!</h1>
<p>Do you love puzzlers?
Did you miss puzzlers?</p>
<p>We recently published a new <a href="https://twitter.com/selenide/status/1560192824536088580">puzzler in Twitter</a>:</p>
<blockquote>
<p>Do these lines work equally? Or is there some difference?</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="answer-options">Answer options</h3>
<p>You gave us many answers:</p>
<ul>
<li>both lines work equally (the most popular answer)</li>
<li>the first case is “logical or”, and the second is “logical and”</li>
<li>the second runs %timeout% seconds longer</li>
<li>the first runs with one timeout, the second run with two timeouts</li>
<li>the first fails if one of conditions is false, the second fails if the element is not visible, but is enabled.</li>
</ul>
<h3 id="correct-answer">Correct answer</h3>
<p>In most cases both variants work equally.</p>
<p>Both variants is “logical AND”. In both cases Selenide will check that the element matches both conditions.</p>
<table>
<tbody>
<tr>
<td> </td>
<td><strong>enabled</strong></td>
<td><strong>disabled</strong></td>
</tr>
<tr>
<td><strong>visible</strong></td>
<td>ok</td>
<td>nok</td>
</tr>
<tr>
<td><strong>invisible</strong></td>
<td>nok</td>
<td>nok</td>
</tr>
</tbody>
</table>
<p><br /></p>
<p>But there is a nuance.</p>
<h3 id="the-nuance">The nuance</h3>
<p>The difference will appear if the element meets the conditions not immediately, but after some time.
Moreover, the first condition should be met in less than 4 seconds, and the second - in more than 4 seconds.
(Say, it gets visible after 3.5 seconds, and enabled - after more 3.5 seconds).</p>
<blockquote>
<p>The thing is that the method <code class="language-plaintext highlighter-rouge">shouldHave</code> has the timeout (by default 4 seconds), while conditions
(<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>) don’t have any timeouts - they can just check “matches” or “doesn’t match”.</p>
</blockquote>
<h3 id="example">Example</h3>
<p>For example, let’s open <a href="https://selenide.org/traffic-light.html">Traffic light</a>.
The light gets green after 3.5 seconds, and after next 3.5 seconds a text “Go!” appears on it.</p>
<p>The first variant checks if the light gets both color and text during 4 seconds:</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">// timeout 4 seconds</span>
</code></pre></div></div>
<p>This variant fails because the light doesn’t get both color and text in 4 seconds (it gets the text “Go” after 7 seconds).</p>
<p>The second variant will not fail:</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">// timeout 4 seconds</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">// another timeout 4 seconds</span>
</code></pre></div></div>
<p>The first <code class="language-plaintext highlighter-rouge">shouldHave</code> waits until the element gets green (and it gets during 4 seconds).
Then the second <code class="language-plaintext highlighter-rouge">shouldHave</code> gets started which waits until the element gets text “Go!” (and it gets it during next 4 seconds).</p>
<p>Apparently, the closest answer was “the first runs with one timeout, the second run with two timeouts”.</p>
<h3 id="your-puzzlers">Your puzzlers?</h3>
<p>Do you have your own puzzlers?
Share with us! Send us! Send’em all! Let’s guess them together!</p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.7.22022-08-14T00:00:00+00:00https://selenide.org/2022/08/14/selenide-6.7.2
<p><br /></p>
<h1 id="good-sunday">Good Sunday!</h1>
<p><br />
We made a mini-release <a href="https://github.com/selenide/selenide/milestone/162?closed=1">Selenide 6.7.2</a> fixing a few memory leaks.</p>
<p>But don’t worry, they are non-critical. It is unlikely that any of you even noticed them.</p>
<h3 id="fix-selenide-memory-leak">Fixed a memory leak with shutdown hooks in Selenide</h3>
<p>If you open and close a browser multiple times in a test</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"><</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>then memory consumption starts growing:</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>It’s caused by shutdown hooks that Selenide adds for every opened browser. And never removes them until the end of JVM.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1917">issue 1917</a>
and <a href="https://github.com/selenide/selenide/pull/1919">PR 1919</a>.</p>
<p>After upgrading to version 6.7.2, memory consumption doesn’t grow anymore:</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><br /></p>
<h3 id="fix-little-proxy-memory-leak">Fixed a memory leak in LittleProxy</h3>
<p>We upgraded to LittleProxy 2.0.11 which also contains a memory leak fix.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/1918">PR 1918</a>
and <a href="https://github.com/LittleProxy/LittleProxy/pull/141">PR 141</a></p>
<p><br /></p>
<h3 id="upgrade-to-selenium-4.4.0">Upgraded to Selenium 4.4.0</h3>
<p>which even contains one my personal fix! Which, by the way, helped us fix the next problem.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/1913">PR 1913</a>
and <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">Selenium changelog</a></p>
<p><br /></p>
<h3 id="fix-full-size-screenshot">Fixed <code class="language-plaintext highlighter-rouge">full-size-screenshot</code> plugin</h3>
<p>Our new plugin <code class="language-plaintext highlighter-rouge">full-size-screenshot</code> had one known problem (caused by a known bug in Selenium):
if you run a browser remotely and open multiple tabs or windows, Selenide might take screenshot from a wrong window.</p>
<p>This bug was fixed in Selenium 4.4.0, and now in Selenide too.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/1920">PR 1920</a> and <a href="https://github.com/SeleniumHQ/selenium/pull/10811">PR 10811</a>.</p>
<p><br /></p>
<h3 id="news">Links</h3>
<ul>
<li>Post <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>Video <a href="https://www.youtube.com/watch?v=0vlV8_4EDAg&t=318s&ab_channel=AutomationBro-DilpreetJohal">Selenide Java Tutorial Series</a> by Automation Bro, 13.06.2022</li>
<li>Post <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>
</ul>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.7.02022-08-04T00:00:00+00:00https://selenide.org/2022/08/04/selenide-6.7.0
<p><br /></p>
<h1 id="good-day">Good day!</h1>
<p><br />
We’ve got a big release <a href="https://github.com/selenide/selenide/milestone/154?closed=1">Selenide 6.7.0</a></p>
<h3 id="holy-whole-string">Now <code class="language-plaintext highlighter-rouge">$.shouldHave(text)</code> can verify the whole text</h3>
<p>From the very beginning, command <code class="language-plaintext highlighter-rouge">$.shouldHave(text)</code> verified the text <em>partially</em>, not the whole text:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt"><div</span> <span class="na">id=</span><span class="s">"freedom-to"</span><span class="nt">></span>Britney Spears<span class="nt"></div></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>Initially, this seemed like a good idea, because a web page often contains all sorts of inconsiderable/invisible characters.
(newlines, tab characters, non-portable spaces, multiple spaces, etc.).</p>
<p>But now it seems that it was still a bad idea, because beginners assume by default that the text is verified entirely, and
snatch their portion of WTF moments when they discover that all their checks were checking a little wrong. :)</p>
<p>And Selenide learned to ignore differences in the inconsiderable characters (for example, multiple subsequent spaces/tabs/newlines are considered as a single space).</p>
<p>NB! Since this change is too drastic and will probably break a bunch of your tests, we left the previous behaviour as a default.
And the new one can be enabled with this setting:</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>And when you need to check a substring, you can use the new check <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>Perhaps we will enable this mode by default in the next major version of Selenide 7.0.0 - until then
<strong>you can play around and give us feedback</strong>.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1780">issue 1780</a> and <a href="https://github.com/selenide/selenide/pull/1783">PR 1783</a>.</p>
<p><br /></p>
<h3 id="full-size-screenshots">Full-size screenshots</h3>
<p>Finally!</p>
<p>Now Selenide can take full-size screenshots.</p>
<p>When a test fails, Selenide automatically takes a screenshot to help you understand why the test failed.
By default, the webdriver captures only the visible part, not the entire browser window. But the most important things
are often located outside the screen. The test failure is often caused by some disabled button at the bottom of the
screen or a pop-up notification somewhere in the corner.</p>
<p>Now you can apply a plugin that takes a screenshot with the full content of a web page in one line:</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. This plugin works only in browser supporting CDP (Chrome, Edge etc.) and Firefox.
In other browsers, Selenide will take standard screenshots as usually.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1799">issue 1799</a> and <a href="https://github.com/selenide/selenide/pull/1858">PR 1858</a>.
Thanks to <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/1800">PR 1800</a>.</p>
<p><br /></p>
<h3 id="cache-lookup-annotation">Caching of page object elements</h3>
<p>As you know, Selenide supports “standard” Selenium page objects with annotations like <code class="language-plaintext highlighter-rouge">@FindBy</code>.
But one specific annotation <code class="language-plaintext highlighter-rouge">@CacheLookup</code> was not supported by Selenide.
It seemed an unneeded optimization because during test run, most of the time is usually spent on other things.</p>
<p>Now we support the caching, why not. Who knows, probably has so much optimized project that the search of web elements
became a bottleneck. I would like to see such a project. :)</p>
<p>Thanks to <a href="https://github.com/groov1kk">Ilya Koshaleu</a> for <a href="https://github.com/selenide/selenide/pull/1894">PR 1894</a>.</p>
<p>P.S. The question arises, should we also add caching for regular <code class="language-plaintext highlighter-rouge">$</code> and <code class="language-plaintext highlighter-rouge">$$</code> as well.
What should be the api: a parameter, a setting? New method?</p>
<p><strong>Suggest your ideas!</strong></p>
<p><br /></p>
<h3 id="cancel-report-testng-annotation">Cancelled TestNG annotation <code class="language-plaintext highlighter-rouge">@Report</code></h3>
<p>Now the cancel culture has reached the annotations!</p>
<p>If you use TestNG and Selenide text report, this announce is for you. Until now, you had to add 2 annotations
to your tests:</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>Why we did this is a long story about the clumsy principles of how listeners work in TestNG
(in short: adding a listener annotation to one class suddenly affects all other classes).
But now we realized that the system can be simplified: the <code class="language-plaintext highlighter-rouge">@Report</code> annotation is no longer needed.</p>
<p>Now Selenide report will be generated for all tests annotated with <code class="language-plaintext highlighter-rouge">@Listeners({TextReport.class}</code> <strong>and their child classes</strong>.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1891">issue 1891</a> and <a href="https://github.com/selenide/selenide/pull/1909">PR 1909</a>.</p>
<p><br /></p>
<h3 id="decode-downloaded-file-name">Decode downloaded file name</h3>
<p>It turned out that when downloading a file, the file name in the server response is sometimes encoded in Base64.
And Selenide was reading this encoded file name as is. Now Selenide decrypts the file name.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1886">issue 1886</a> and <a href="https://github.com/selenide/selenide/pull/1889">PR 1889</a>.</p>
<p><br /></p>
<h3 id="restore-ie-support-set-value">Fixed <code class="language-plaintext highlighter-rouge">$.setValue()</code> in IE</h3>
<p>It turns out we recently broke the <code class="language-plaintext highlighter-rouge">$.setValue()</code> method in Internet Explorer.
We assumed people don’t use IE anymore: IE has officially given up. But there were complaints, and we restored IE support.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/1907">PR 1907</a>.</p>
<p><br /></p>
<h3 id="made-http-client-timeouts-public">Made <code class="language-plaintext highlighter-rouge">HttpClientTimeouts</code> public</h3>
<p>See <a href="https://github.com/selenide/selenide/pull/1902">PR 1902</a>.</p>
<p><br /></p>
<h3 id="restore-set-value-string">Returned parameter type to <code class="language-plaintext highlighter-rouge">String</code> for method <code class="language-plaintext highlighter-rouge">$.setValue()</code></h3>
<p>Personally, it burns me from the fact that such a problem arose at all.</p>
<p>See details in <a href="https://github.com/selenide/selenide/issues/1885">issue 1885</a> and <a href="https://github.com/selenide/selenide/pull/1888">PR 1888</a>.</p>
<p><br /></p>
<h3 id="validate-file-extension">Added a warning about invalid file extension parameter</h3>
<p>See <a href="https://github.com/selenide/selenide/pull/1887">PR 1887</a>.</p>
<p><br /></p>
<h3 id="update-dependencies">Updated 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>restored parameter <code class="language-plaintext highlighter-rouge">Driver</code> in method <code class="language-plaintext highlighter-rouge">SelenidePageFactory.findSelector()</code> - it’s used by <code class="language-plaintext highlighter-rouge">selenide-appium</code> plugin.</li>
</ul>
<p><br /></p>
<h3 id="news">News</h3>
<ul>
<li><a href="https://github.com/iSYS-Software/SelenideReporter">Opinionated reporting framework for Selenide</a> by Ulrich Mayring</li>
<li><a href="https://www.youtube.com/watch?v=-KGtZoFVzr8&list=PL9Z-JgiTsOYRfoG_mcRBlTUIFPIknhQ6S">Extending open-source libraries: Selenide & Selenium</a> - Selenium Conf, 30.07.2022</li>
<li><a href="https://www.youtube.com/watch?v=-c5XT2v5gRY&ab_channel=DEVCLUB.EE">Flaky Tests</a> - devclub.ee, Tallinn, 05.07.2022</li>
</ul>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.6.62022-07-01T00:00:00+00:00https://selenide.org/2022/07/01/selenide-6.6.6
<p><br /></p>
<h1 id="good-evening">Good evening!</h1>
<p><br />
We made another release <a href="https://github.com/selenide/selenide/milestone/160?closed=1">Selenide 6.6.6</a></p>
<h3 id="remove-deprecated-capabilities">Removed deprecated capabilities</h3>
<p>Some webdriver options (which Selenide has been setting for years) were later marked as deprecated.<br />
Starting from some release, Selenium started logging warnings about them.</p>
<p>Now Selenide doesn’t set them anymore: <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>.</p>
<p>We will not forget you, friends! You have served us faithfully for over 10 years.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1862">issue 1862</a>, <a href="https://github.com/selenide/selenide/issues/1866">issue 1866</a>
and <a href="https://github.com/selenide/selenide/pull/1870">PR 1870</a>.</p>
<p><br /></p>
<h3 id="fix-clear-with-shortcut">Fixed ClearWithShortcut</h3>
<p>… when working with driver wrapped into listeners. It’s rare, don’t worry.</p>
<p>Thanks to <a href="https://github.com/petroOv-PDFfiller">Petro Ovcharenko</a> for <a href="https://github.com/selenide/selenide/pull/1856">PR 1856</a>.</p>
<p><br /></p>
<h3 id="shorter-syntax-for-click">Added shorter syntax for <code class="language-plaintext highlighter-rouge">$.click</code></h3>
<p>If you wished to click with an offset or custom timeout, you had to write quite a long line:</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>Now you can write a shorter line:</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>See <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">Added support for mobile apps</h3>
<p>… when checking if webdriver is still alive.</p>
<p>This is a minor fix for <code class="language-plaintext highlighter-rouge">selenide-appium</code>.</p>
<p>When you reuse the same webdriver for multiple tests, Selenide needs to regularly check if the webdriver is still alive.
To check it, Selenide calls <code class="language-plaintext highlighter-rouge">WebDriver.getTitle()</code>.</p>
<p>Recently we realised that method <code class="language-plaintext highlighter-rouge">getTitle()</code> is not supported in Appium. Now we handle this situation properly, and
the browser health check works in Appium too.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1878">issue 1878</a> and <a href="https://github.com/selenide/selenide/pull/1879">PR 1879</a>.</p>
<p><br /></p>
<h3 id="fix-reopen-browser-on-fail">Fixed logic of <code class="language-plaintext highlighter-rouge">reopenBrowserOnFail</code> setting</h3>
<p>Another improvement for testing mobile apps.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1880">issue 1880</a> and <a href="https://github.com/selenide/selenide/pull/1881">PR 1881</a>.</p>
<p><br /></p>
<h3 id="update-dependencies">Upgraded dependencies</h3>
<ul>
<li>WebDriverManager <a href="https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md">from 5.2.0 to 5.2.1</a>.</li>
<li>byteBuddyVersion <a href="https://github.com/selenide/selenide/pull/1872">from 1.12.11 to 1.12.12</a>.</li>
</ul>
<p><br /></p>
<h3 id="release-selenide-appium-2.1.0">Released selenide-appium 2.1.0</h3>
<p>This version contains improved support for running tests for iOS applications.</p>
<p>See <a href="https://github.com/selenide/selenide-appium/blob/master/CHANGELOG">selenide-appium</a>.</p>
<p><br /></p>
<p><em>With this release, we decided to demonstrate to the world community that we do not interfere with the creation of automated tests for mobile applications.</em></p>
<p><em>Now it’s up to the automators.</em></p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.6.42022-06-20T00:00:00+00:00https://selenide.org/2022/06/20/selenide-6.6.4
<p><br /></p>
<h1 id="gootas-morningas">Gootas morningas!</h1>
<p><br />
We made another mini-released <a href="https://github.com/selenide/selenide/milestone/158?closed=1">Selenide 6.6.4</a>.</p>
<h3 id="exact-texts-case-sensitive">Added condition <code class="language-plaintext highlighter-rouge">exactTextsCaseSensitive</code> for collections</h3>
<p>Selenide has several built-in checks for collections texts:</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">// etc.</span>
</code></pre></div></div>
<p>Now there is one more check available:</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>Thanks to <a href="https://github.com/ben-nc2">Ben Heap</a> for <a href="https://github.com/selenide/selenide/pull/1861">PR 1861</a>.</p>
<p><br /></p>
<h3 id="selected-option-lazy-loaded">Made method <code class="language-plaintext highlighter-rouge">$.getSelectedOption()</code> lazy</h3>
<p>By design, (almost) all Selenide methods <a href="https://github.com/selenide/selenide/wiki/Lazy-loading">should be lazy</a>.</p>
<p>For example, call to <code class="language-plaintext highlighter-rouge">$("#nope")</code> does NOT fail even if the element doesn’t exist. It allows writing negative checks, e.g.</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>We realized we method <code class="language-plaintext highlighter-rouge">$("select").getSelectedOption()</code> was not lazy. It failed immediately if the select was not
loaded yet etc.<br />
So you could not write such a negative check:</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">// failed on this line</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>Now we have corrected this issue. <em>The laziness won!</em>
See <a href="https://github.com/selenide/selenide/issues/1581">issue 1581</a> and <a href="https://github.com/selenide/selenide/pull/1864">PR 1864</a>.</p>
<p><br /></p>
<h3 id="update-dependencies">Updated dependencies</h3>
<ul>
<li>Netty <a href="https://github.com/selenide/selenide/pull/1857">from 4.1.77.Final to 4.1.78.Final</a>.</li>
<li>BrowserUp proxy <a href="https://github.com/selenide/selenide/pull/1860">from 2.1.5 to 2.2.0</a>.</li>
</ul>
<p><br /></p>
<h3 id="release-selenide-6.6.5">UPD Released Selenide 6.6.5</h3>
<p>One more mini-release <a href="https://github.com/selenide/selenide/milestone/159?closed=1">Selenide 6.6.5</a>.</p>
<p>Upgraded Selenium from 4.2.2 to 4.3.0.</p>
<p><br />
<br /></p>
<p><em>This is our frank response to your frank request.</em></p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.6.32022-06-12T00:00:00+00:00https://selenide.org/2022/06/12/selenide-6.6.3
<p><br /></p>
<h1 id="good-evening-fellows">Good evening fellows!</h1>
<p><br />
We made a mini-release <a href="https://github.com/selenide/selenide/milestone/157?closed=1">Selenide 6.6.3</a>.</p>
<h3 id="improve-click-timeout">Improved timeout for <code class="language-plaintext highlighter-rouge">$.click()</code></h3>
<p>In version 6.6.0, we added an optional parameter <code class="language-plaintext highlighter-rouge">timeout</code> for method <code class="language-plaintext highlighter-rouge">$.click()</code>.<br />
But it appeared that it <a href="/2022/06/08/selenide-6.6.0/#click-timeout">only partially</a> solved the problem.</p>
<p>Now we improved it: method</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>waits 8 seconds for both the element itself and the following page loading.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1572">issue 1572</a> and <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 day before, we released <a href="https://github.com/selenide/selenide/milestone/156?closed=1">Selenide 6.6.2</a> with upgrade to Selenium 4.2.2</p>
<p>See <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>Before this, we released <a href="https://github.com/selenide/selenide/milestone/155?closed=1">Selenide 6.6.1</a>
with a tiny fix for an old <a href="https://github.com/selenide/selenide/issues/1850">issue 1850</a>.
We restore <code class="language-plaintext highlighter-rouge">byte-buddy</code> dependency which was needed for adding listeners to webdriver.</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.6.02022-06-08T00:00:00+00:00https://selenide.org/2022/06/08/selenide-6.6.0
<p><br /></p>
<h1 id="good-morning-friends">Good morning, friends!</h1>
<p><br />
We released <a href="https://github.com/selenide/selenide/milestone/152?closed=1">Selenide 6.6.0</a>.</p>
<h3 id="selenide-clear-with-shortcut">Added new Selenide plugin <code class="language-plaintext highlighter-rouge">selenide-clear-with-shortcut</code></h3>
<p>In Selenide 6.5.0, we changed the implementation of <code class="language-plaintext highlighter-rouge">$.clear()</code> method from a standard WebDriver to a shortcut (“Select all” -> “Delete”).<br />
Later we realized this shortcut didn’t work stably in all browsers, we had to rework it. It got more stable, but slower.
And since it’s not really needed for all, we decided to return the old good <code class="language-plaintext highlighter-rouge">WebElement.clear()</code>.</p>
<p>And if you need the <em>smart</em> <code class="language-plaintext highlighter-rouge">$.clean()</code> method with shortcuts - you can add the brand new Selenide plugin:</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>Dependency <code class="language-plaintext highlighter-rouge">com.codeborne:selenide-clear-with-shortcut</code> will override method <code class="language-plaintext highlighter-rouge">$.clear()</code> - and <code class="language-plaintext highlighter-rouge">$.setValue()</code> correspondingly.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1497">issue 1497</a>, <a href="https://github.com/selenide/selenide/pull/1847">PR 1847</a> and <a href="https://github.com/selenide/selenide/pull/1838">PR 1838</a>.</p>
<p><br /></p>
<h3 id="fix-clear-in-safari">Fix method <code class="language-plaintext highlighter-rouge">$.clear()</code> in Safari</h3>
<p>We found that new <code class="language-plaintext highlighter-rouge">$.clear()</code> didn’t work in Safari browser (who uses it nowadays?). <br />
I hope we fixed it. :)</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1819">issue 1819</a> and <a href="https://github.com/selenide/selenide/pull/1820">PR 1820</a>.</p>
<p><br /></p>
<h3 id="new-own-test-checks">New checks for element own text</h3>
<p>Added two new checks for element’s 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>Thanks to <a href="https://github.com/kachurinaa">Kachurin Alexandr</a> for
<a href="https://github.com/selenide/selenide/pull/1811">PR 1811</a> and <a href="https://github.com/selenide/selenide/pull/1812">PR 1812</a>.</p>
<p><br /></p>
<h3 id="click-timeout">Added method <code class="language-plaintext highlighter-rouge">$.click()</code> with timeout</h3>
<p>By default, method <code class="language-plaintext highlighter-rouge">$.click()</code> has the standard Selenide timeout (which is initially 4 seconds).<br />
Sometimes it’s not enough - for example:</p>
<ol>
<li>if clicking a link opens a new page which loads longer than 4 seconds.</li>
<li>if the element which we are going to click is not visible yet, and appears after more than 4 seconds.</li>
</ol>
<p>In this release, we added timeout parameter to method <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>Though, it solves only the first problem. In next release we will also solve the second. :)</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1572">issue 1572</a> and <a href="https://github.com/selenide/selenide/pull/1845">PR 1845</a>.</p>
<p><br /></p>
<h3 id="modal-timeout">Added timeout to methods <code class="language-plaintext highlighter-rouge">confirm()</code>, <code class="language-plaintext highlighter-rouge">dismiss()</code> and <code class="language-plaintext highlighter-rouge">prompt()</code></h3>
<p>These methods existed from the very beginning of Selenide era. They allow working with JavaScript modal dialogs (<code class="language-plaintext highlighter-rouge">alert</code>, <code class="language-plaintext highlighter-rouge">confirm</code>, <code class="language-plaintext highlighter-rouge">prompt</code>).
For example:</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>But they could not have any other timeout except the default one.
Now you can pass a timeout parameter:</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>See <a href="https://github.com/selenide/selenide/issues/1721">issue 1721</a> and <a href="https://github.com/selenide/selenide/pull/1846">PR 1846</a>.</p>
<p><br /></p>
<h3 id="fix-execute-javascript">Fixed method <code class="language-plaintext highlighter-rouge">Driver.executeJavaScript()</code></h3>
<p>…to support a wrapped webdriver (i.e. when you have added some listeners to the webdriver).</p>
<p>See <a href="https://github.com/selenide/selenide/pull/1848">PR 1848</a>.</p>
<p><br /></p>
<h3 id="fix-checks-wording">Fixed phrasing of some checks</h3>
<p>… to sound correctly in English. Namely:</p>
<table>
<thead>
<tr>
<th>In a test</th>
<th>Was in report</th>
<th>Now in report</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>See <a href="https://github.com/selenide/selenide/pull/1840">PR 1840</a>.</p>
<p><br /></p>
<h3 id="restore-safari-options">Restored Safari options</h3>
<p>We realized that after upgrading to Selenium 4, we lost most of Safari options.<br />
It was easy to fix, yet… why nobody did complain on it?</p>
<p>Looks like nobody is using Safari… :)</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1836">issue 1836</a> and <a href="https://github.com/selenide/selenide/pull/1841">PR 1841</a>.</p>
<p><br /></p>
<h3 id="fix-testng-soft-asserts">Fixed soft asserts in TestNG</h3>
<p>After upgrading to TestNG 7.5, Selenide soft asserts didn’t work anymore. If some check failed, your tests still remained green.</p>
<p>We had to downgrade to TestNG 7.4.0 and hope for the fix on the dark side. :)</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1834">issue 1834</a> and <a href="https://github.com/selenide/selenide/pull/1843">PR 1843</a>.</p>
<p><br /></p>
<h3 id="update-dependencies">Upgraded dependencies</h3>
<ul>
<li>Selenium <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">4.1.4 -> 4.2.1</a>.</li>
<li>WebDriverManager <a href="https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md">5.1.1 -> 5.2.0</a></li>
</ul>
<p><br /></p>
<h3 id="statistics">Statistics</h3>
<p>We haven’t published Selenide download statistics for a long time:</p>
<center>
<img src="/images/2022/06/selenide.downloads.png" width="800" />
</center>
<p>We’re almost back to our all-time high of 324k downloads in May.</p>
<p><br /></p>
<p>Stay tuned!</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.5.02022-05-17T00:00:00+00:00https://selenide.org/2022/05/17/selenide-6.5.0
<p><br /></p>
<h1 id="good-night">Good night!</h1>
<p><br />
We released <a href="https://github.com/selenide/selenide/milestone/151?closed=1">Selenide 6.5.0</a>.</p>
<h3 id="now-you-can-mask-passwords-in-reports">Now you can mask passwords in reports</h3>
<p>Sometimes you need to type passwords and other sensitive data into input fields. Sometimes people don’t want this
data to be visible in test reports (e.g. Allure or TextReport). And ask to hide this sensitive data somehow.</p>
<p>I personally never understood why it’s a problem.<br />
Why the password from test environment should be a problem?<br />
You don’t use the same password in production, right?<br />
You don’t run tests in production, right?</p>
<p>Anyway, we made it possible to mask sensitive data in test reports:</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">// replaces by "********"</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">// replaces by "J* username"</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/1768">issue 1768</a> and <a href="https://github.com/selenide/selenide/pull/1770">PR 1770</a>.</p>
<p><br /></p>
<h3 id="now-you-can-easily-pick-a-date-in-input-typedate">Now you can easily pick a date in <code class="language-plaintext highlighter-rouge"><input type=date></code></h3>
<p>It’s not a trivial task to pick a date in Selenium.</p>
<p>When your application has element like <code class="language-plaintext highlighter-rouge"><input type=date></code>, and your test tries to click it, different browsers open
different calendars and use different date formats. In theory, they should use format based on user settings, but in
reality each browser plays its own game.</p>
<p>This causes flaky tests that might work on your machine, but occasionally fail on others.</p>
<p>As a result of my investigation, I found that the only stable way to pick a date is setting a value in format
<code class="language-plaintext highlighter-rouge">yyyy-mm-dd</code> using JavaScript snippet. It seems to work in all OSs and browsers.</p>
<p>Now you can easily do it with new method <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>See <a href="https://github.com/selenide/selenide/issues/1753">issue 1753</a> and <a href="https://github.com/selenide/selenide/pull/1770">PR 1770</a>.</p>
<p><br /></p>
<h3 id="now-method-setvalue-supports-react-vuejs-etc">Now method <code class="language-plaintext highlighter-rouge">$.setValue("")</code> supports React, Vue.js etc.</h3>
<p>Standard Selenium method <code class="language-plaintext highlighter-rouge">WebElement.clean()</code> (e.g. it’s used in Selenide method <code class="language-plaintext highlighter-rouge">$.setValue()</code>) doesn’t always work
when the application uses some tricky constructions (generated by React/Vue/…) instead of standard <code class="language-plaintext highlighter-rouge"><input></code>.</p>
<p>Hopefully, we have fixed it. Waiting for your feedback.</p>
<p>Now the following 2 methods abandoned using <code class="language-plaintext highlighter-rouge">WebElement.clear()</code>. They use key combinations instead:</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>This new way seems to work in all OSs and browsers.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1497">issue 1497</a> and <a href="https://github.com/selenide/selenide/pull/1787">PR 1787</a>.</p>
<p>Thanks to <a href="https://github.com/vinogradoff">Alexei Vinogradov</a> for the research in <a href="https://github.com/selenide/selenide/pull/1499">PR 1499</a>.</p>
<p><br /></p>
<h3 id="removed-triggering-duplicate-blur-and-change-events">Removed triggering duplicate <code class="language-plaintext highlighter-rouge">blur</code> and <code class="language-plaintext highlighter-rouge">change</code> events</h3>
<p>As a result of previous change, method <code class="language-plaintext highlighter-rouge">$.setValue("blah")</code> triggers <code class="language-plaintext highlighter-rouge">blur</code> and <code class="language-plaintext highlighter-rouge">change</code> events only once.</p>
<p>Before this release, method <code class="language-plaintext highlighter-rouge">$.setValue("blah")</code> worked in two steps and therefore triggered events twice:</p>
<ul>
<li>Step 1. <code class="language-plaintext highlighter-rouge">$.clear()</code> // triggered <code class="language-plaintext highlighter-rouge">blur</code> and <code class="language-plaintext highlighter-rouge">change</code></li>
<li>Step 2. <code class="language-plaintext highlighter-rouge">$.sendKeys("blah")</code> // triggered <code class="language-plaintext highlighter-rouge">blur</code> and <code class="language-plaintext highlighter-rouge">change</code> once more</li>
</ul>
<p>The events triggered on the first step could cause unexpected effects, including disappearing of the field itself.<br />
See <a href="https://github.com/selenide/selenide/issues/960">issue 960</a>.</p>
<p><br /></p>
<h3 id="trigger-blur-on-a-previous-element">Trigger <code class="language-plaintext highlighter-rouge">blur</code> on a previous element</h3>
<p>During working on the previous change, we improved method <code class="language-plaintext highlighter-rouge">$.setValue("blah")</code> so that it triggers <code class="language-plaintext highlighter-rouge">blur</code> event on a
previous active element. At least it helped to fix some of our flaky tests. Hopefully, it can improve your tests as well.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1784">issue 1784</a> and <a href="https://github.com/selenide/selenide/commit/593e6fc900500d9">commit 593e6fc9005</a>.</p>
<p><br /></p>
<h3 id="now-method-setvalue-and-append-check-that-element-is-not-disabled-or-readonly">Now method <code class="language-plaintext highlighter-rouge">$.setValue()</code> and <code class="language-plaintext highlighter-rouge">$.append()</code> check that element is not disabled or readonly</h3>
<p>See <a href="https://github.com/selenide/selenide/issues/1523">issue 1523</a> and <a href="https://github.com/selenide/selenide/pull/1787">PR 1787</a>.</p>
<p><br /></p>
<h3 id="added-conditions-interactable-and-editable">Added conditions “interactable” and “editable”</h3>
<p>These conditions existed inside of Selenide, but were not available to end-users. <br />
Now you can also use them:</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>See <a href="https://github.com/selenide/selenide/issues/1523">issue 1523</a> and <a href="https://github.com/selenide/selenide/pull/1787">PR 1787</a>.</p>
<p><br /></p>
<h3 id="method-downloadfolder-waits-for-full-download-completion">Method <code class="language-plaintext highlighter-rouge">$.download(FOLDER)</code> waits for full download completion</h3>
<p>Sometimes test might be flaky when it tries to download a file which is being downloaded very slowly. Selenide might
detect and copy the file in <code class="language-plaintext highlighter-rouge">C:\Downloads</code> folder which is not fully downloaded yet.</p>
<p>Now Selenide waits until <code class="language-plaintext highlighter-rouge">C:\Downloads</code> doesn’t contain any files “<em>.crdownload” (for Chrome) or “</em>.part” (for Firefox).
This is a temporary file created by the browser for a short period of time while the file is beging downloaded.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1779">issue 1779</a>,
<a href="https://github.com/selenide/selenide/pull/1804">PR 1804</a> and <a href="https://github.com/selenide/selenide/pull/1769">PR 1769</a>.</p>
<p><br /></p>
<h3 id="added-method-stream-for-collections">Added method <code class="language-plaintext highlighter-rouge">stream()</code> for collections</h3>
<p>Actually, method <code class="language-plaintext highlighter-rouge">$$.stream()</code> already existed, but was deprecated in version <a href="/2022/01/10/selenide-6.2.0/">6.2.0</a>.
Now you can pick one of two non-deprecated replacements:</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>See <a href="https://github.com/selenide/selenide/issues/1773">issue 1773</a> and <a href="https://github.com/selenide/selenide/pull/1774">PR 1774</a>.</p>
<p><br /></p>
<h3 id="remove-selenium-built-in-opentelemetry">Remove Selenium built-in OpenTelemetry</h3>
<p>If I am not mistaken, this “telemetry” was added Selenium 4.
I have no idea why it’s needed, but it could interfere with someone who already had their own telemetry. <br />
It was simpler for us to remove it than support both. :)</p>
<p>Thanks to <a href="https://github.com/zzz">Petro Ovcharenko</a> and <a href="https://github.com/zzz">Aliaksandr Rasolka</a>
for <a href="https://github.com/selenide/selenide/pull/1763">PR 1763</a>.</p>
<p><br /></p>
<h3 id="upgraded-dependencies">Upgraded dependencies</h3>
<ul>
<li>Selenium <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">4.1.3 -> 4.1.4</a>.</li>
<li>WebDriverManager <a href="https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md">5.1.0 -> 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 -> 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 -> 4.1.77.Final</a></li>
<li>LittleProxy <a href="https://github.com/LittleProxy/LittleProxy/releases">2.0.7 -> 2.0.9</a></li>
</ul>
<p>By the way LittleProxy projects moved to a dedicated <a href="https://github.com/LittleProxy/LittleProxy">github organisation</a>,
and I became the main maintainer of the project. I was never a big fan of proxies, but LittleProxy is used inside of
Selenide, and somebody needs to maintain it…</p>
<p><br /></p>
<h1 id="upd-selenide-651">UPD Selenide 6.5.1</h1>
<p>A small update <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> Fixed <code class="language-plaintext highlighter-rouge">$.clear()</code> so that it doesn’t press <code class="language-plaintext highlighter-rouge">tab</code> anymore – see <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> Bump browserup-proxy-core 2.1.4 to 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> Fixed method <code class="language-plaintext highlighter-rouge">$.clear()</code> on a fresh Firefox: now it
presses “Ctrl+A -> Delete” instead of “Home -> Shift+A -> Delete”.
See <a href="https://github.com/selenide/selenide/pull/1838">PR #1838</a>.</p>
<p><br /></p>
<p>Stay tuned!</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.4.02022-04-07T00:00:00+00:00https://selenide.org/2022/04/07/selenide-6.4.0
<p><br /></p>
<h1 id="good-evening-friends">Good evening, friends!</h1>
<p><br />
We released <a href="https://github.com/selenide/selenide/milestone/145?closed=1">Selenide 6.4.0</a>.</p>
<p><br /></p>
<h2 id="now-we-show-both-alias-and-locator-on-test-failure">Now we show both alias and locator on test failure</h2>
<p>In Selenide, you can use method <code class="language-plaintext highlighter-rouge">as</code> to give web elements readable names.<br />
It may be useful when the element has no good ID/class, and you have no choice but write long ugly unreadable xpath.
It’s hard to read such selectors in reports.</p>
<p>Sample usage of <code class="language-plaintext highlighter-rouge">as</code>:</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>We always had a dilemma: should Selenide</p>
<ol>
<li>show only alias (pros: easily readable, cons: locator is not visible - but it might be helpful)</li>
<li>show both alias and locator (pros: locator is visible, cons: hard to read).</li>
</ol>
<p><br /></p>
<p>Finally, we realized what is the right way.</p>
<p>Starting from version 6.4.0, Selenide will:</p>
<ol>
<li>Show only alias in reports (@TextReport, Allure report etc.)</li>
<li>Show both alias and locator in error message in case of test failure</li>
</ol>
<p>For example, the code mentioned above will look like this in report:</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>And in error message:</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>See <a href="https://github.com/selenide/selenide/issues/1765">issue 1765</a> and <a href="https://github.com/selenide/selenide/pull/1766">PR 1766</a>.</p>
<p><br /></p>
<h2 id="added-spaces-in-selenide-report">Added spaces in Selenide report</h2>
<p>The report mentioned above looked like this until now:</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>The problem is that the long URL is wrapped with <code class="language-plaintext highlighter-rouge">|</code> characters on the left and right. It makes it impossible to
easily select it with double click. Now a space will be added to the left and right of the URL and other values in the report.</p>
<p>And the report looks now nicer, right?</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1764">issue 1764</a> and <a href="https://github.com/selenide/selenide/pull/1767">PR 1767</a>.</p>
<p><br /></p>
<h2 id="upgraded-to-selenium-413">Upgraded to Selenium 4.1.3</h2>
<p>See <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">Selenium changelog</a> and <a href="https://github.com/selenide/selenide/pull/1759">PR 1759</a>.</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.3.02022-02-07T00:00:00+00:00https://selenide.org/2022/02/07/selenide-6.3.0
<p><br /></p>
<h1 id="hello-people">Hello, people!</h1>
<p><br />
We released <a href="https://github.com/selenide/selenide/milestone/143?closed=1">Selenide 6.3.0</a>.</p>
<p>Let’s review what’s changed?</p>
<p><br /></p>
<h1 id="added-methods-switchtoframetimeout-with-custom-timeout">Added methods <code class="language-plaintext highlighter-rouge">switchTo().frame(timeout)</code> with custom timeout</h1>
<p>Selenide has methods <code class="language-plaintext highlighter-rouge">switchTo().frame(name)</code> for switching between frames. As usually, with built-in waiting and other bonuses.<br />
But what if the frame is being loaded longer than the default timeout (4 seconds)?</p>
<p>Now you can pass an additional parameter <code class="language-plaintext highlighter-rouge">Duration</code> - the timeout for switching into the frame:</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">// waits up to default timeout (4 seconds)</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">// waits up to 6 seconds</span>
</code></pre></div></div>
<p>Thanks to <a href="https://github.com/donesvad">@donesvad</a> for <a href="https://github.com/selenide/selenide/pull/1722">PR 1722</a>.</p>
<p><br /></p>
<h1 id="added-selectors-bytagandtext-and-withtagandtext">Added selectors <code class="language-plaintext highlighter-rouge">byTagAndText</code> and <code class="language-plaintext highlighter-rouge">withTagAndText</code></h1>
<p>Selenide has method for finding elements by text:</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>But sometimes it’s not enough: if there are multiple elements with given text, and you need to pick one of them by tag.</p>
<p>Now Selenide has methods for find by tag and text:</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>Thanks to <a href="https://github.com/maurizio-lattuada">Maurizio Lattuada</a> for <a href="https://github.com/selenide/selenide/issues/1650">issue 1650</a> and <a href="https://github.com/selenide/selenide/pull/1651">PR 1651</a>.</p>
<p><br /></p>
<h1 id="fixed-bug-in-bytextcaseinsensitive">Fixed bug in <code class="language-plaintext highlighter-rouge">byTextCaseInsensitive</code></h1>
<p>Now this selector ignores leading/trailing spaces and newlines in the text (like the canonical <code class="language-plaintext highlighter-rouge">byText</code>).</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1723">issue 1723</a> and <a href="https://github.com/selenide/selenide/pull/1724">PR 1724</a>.</p>
<p><br /></p>
<h1 id="added-records-webdriver-create-and-webdriver-close-to-report">Added records “webdriver create” and “webdriver close” to report</h1>
<p>If you use Selenide’s <code class="language-plaintext highlighter-rouge">TextReport</code> or plugin <code class="language-plaintext highlighter-rouge">AllureSelenide</code>, you are used to see the report in the end of every test.<br />
The report shows all the performed steps: open a page - find an element - click etc.</p>
<p>Now the report also shows moments when the webdriver was created or closed. This information may be useful when
debugging some problems with tests.</p>
<p>Thanks to <a href="https://github.com/petroOv-PDFfiller">Petro Ovcharenko</a> for <a href="https://github.com/selenide/selenide/pull/1715">PR 1715</a>.</p>
<p><br /></p>
<h1 id="fixed-overriding-of-selenium-timeout">Fixed overriding of Selenium timeout</h1>
<p>In <a href="/2021/06/08/selenide-5.22.0/">Selenide 5.22.0</a> we introduced a hack for overriding Selenium webdriver timeout from (unreasonably long) 3 hours to 2 minutes.</p>
<p>But this hack was broken after upgrade to Selenium 4 (as it always happens to all hacks).
Now we reanimated it.</p>
<p>Let me remind that Selenide now has the following timeouts in communication between tests and webdriver:</p>
<ul>
<li>connect timeout - 10 seconds</li>
<li>read timeout - 1.5 minutes</li>
</ul>
<p>See <a href="https://github.com/selenide/selenide/commit/cf02da5">commit cf02da5</a>.</p>
<p><br /></p>
<h1 id="removed-duplicate-wrapping-of-element-not-found">Removed duplicate wrapping of “Element not found”</h1>
<p>See <a href="https://github.com/selenide/selenide/issues/1705">issue 1705</a> and <a href="https://github.com/selenide/selenide/pull/1706">PR 1706</a>.</p>
<p><br /></p>
<h1 id="added-support-for-authentication-type-bearer">Added support for authentication type <code class="language-plaintext highlighter-rouge">BEARER</code></h1>
<p>Selenide has several types of authentication:</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>but only <code class="language-plaintext highlighter-rouge">BASIC</code> did really work. Nobody ever tested the other types. :)</p>
<p>And we found that <code class="language-plaintext highlighter-rouge">BEARER</code> type didn’t work. Now we fixed it.</p>
<p>This is how you can use it:</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>See <a href="https://github.com/selenide/selenide/pull/1714">PR 1714</a>.</p>
<p><br /></p>
<h1 id="now-selenide-treats-empty-settings-like-selenideremote-as-undefined">Now Selenide treats empty settings like <code class="language-plaintext highlighter-rouge">selenide.remote</code> as undefined</h1>
<p>This change should make devops’ life easier.
When configuring CI pipelines and jobs, you often use variables to set Selenide settings:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-Dselenide.remote=${env.GRID_URL}
</code></pre></div></div>
<p>If <code class="language-plaintext highlighter-rouge">GRID_URL</code> variable is not set in some environment, Selenide failed because it tried to parse empty url to set <code class="language-plaintext highlighter-rouge">selenide.remote</code>.</p>
<p>Now Selenide will treat empty setting like <code class="language-plaintext highlighter-rouge">selenide.remote</code> just undefined and continue work as usually (like <code class="language-plaintext highlighter-rouge">selenide.remote</code> was never set).</p>
<p>See <a href="https://github.com/vinogradoff">Alexei Vinogradov</a> for <a href="https://github.com/selenide/selenide/issues/1656">issue 1656</a> and <a href="https://github.com/BorisOsipov">Boris Osipov</a> for <a href="https://github.com/selenide/selenide/pull/1663">PR 1663</a>.</p>
<p><br /></p>
<h1 id="upgraded-to-selenium-412">Upgraded to Selenium 4.1.2</h1>
<p>A heard some users experienced problems with Guava version after upgrading to Selenium 4.1.2. Selenide defined Guava version
explicitly, so generally you should not experience such a problem. If you still get something like <code class="language-plaintext highlighter-rouge">NoSuchMethodError</code>, please
verify the guava version: pribably it’s overridden by some Gradle or Maven plugin. Please refer the old good <a href="/2020/11/17/why-proxy-does-not-work-in-selenoid/">post about resolving dependencies</a> if needed.</p>
<p>See <a href="https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG">Selenium changelog</a> and <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>Minor update <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> we restored possibility to use soft asserts in TestNG in methods <code class="language-plaintext highlighter-rouge">@Before*</code> and <code class="language-plaintext highlighter-rouge">@After*</code> (we occasionally forbidden them it Selenide 6.2.0) - see <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> Upgraded from Netty 4.1.73.Final to 4.1.74.Final</li>
</ul>
<p><br /></p>
<h1 id="upd-selenide-632">UPD Selenide 6.3.2</h1>
<p>Another update <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> Added a workaround for Selenium bug <a href="https://github.com/SeleniumHQ/selenium/issues/10345">10345</a>, which caused failure of method <code class="language-plaintext highlighter-rouge">FirefoxDriver.close()</code> after upgrading to Firefox 97.</li>
<li><a href="https://github.com/selenide/selenide/pull/1736">#1736</a> Upgraded from BrowserUpProxy 2.1.3 to 2.1.4</li>
<li><a href="https://github.com/selenide/selenide/pull/1611">#1611</a> Upgraded Java version from 8 to 17.</li>
</ul>
<p>Let me explain the Java update. Now Selenide project is built with Java 17, but the generated binaries <code class="language-plaintext highlighter-rouge">selenide-*.jar</code>
are targeted to Java 8. This allows</p>
<ul>
<li>Selenide developers use all the latest Java features, and</li>
<li>Selenide users still run their tests on Java 8 (though we recommend upgrading Java, of course).</li>
</ul>
<p>It became possible thanks to the tool <a href="https://github.com/bsideup/jabel">Jabel</a> and personally <a href="https://github.com/bsideup">
Sergei Egorov</a> who came up with this elegant hack
(and also involved in <a href="https://github.com/testcontainers/testcontainers-java">TestContainers</a> and <a href="https://www.atomicjar.com/">AtomicJar</a>).</p>
<p><br /></p>
<h1 id="upd-selenide-633">UPD Selenide 6.3.3</h1>
<p>One more minor update <a href="https://github.com/selenide/selenide/milestone/148?closed=1">Selenide 6.3.3</a>:</p>
<ul>
<li>#1737 allow overriding Firefox preferences for downloading files</li>
<li>#1740 upgraded to WebDriverManager 5.1.0</li>
</ul>
<p><br /></p>
<h1 id="upd-selenide-634">UPD Selenide 6.3.4</h1>
<p>Another update <a href="https://github.com/selenide/selenide/milestone/149?closed=1">Selenide 6.3.4</a>:</p>
<ul>
<li>#1746 show the expected attribute when <code class="language-plaintext highlighter-rouge">$.shouldHave(attribute(...))</code> fails.</li>
<li>#1748 fixed module name in generated Selenide binaries</li>
</ul>
<p><br /></p>
<h1 id="upd-selenide-635">UPD Selenide 6.3.5</h1>
<p>Another update <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> fix file download via proxy in case of encoded response - see <a href="https://github.com/selenide/selenide/pull/1756">PR #1756</a></li>
</ul>
<p><br /></p>
<h1 id="news">News</h1>
<ul>
<li>We created a group in LinkedIn: <a href="https://www.linkedin.com/groups/9154550/">Selenide User Group</a>!</li>
<li>Post by Miklós Szeles <a href="https://www.linkedin.com/pulse/selenium-selenide-mikl%25C3%25B3s-szeles/">Selenium or Selenide?</a></li>
<li>Selenide got to compilation <a href="https://qameta.io/blog/5-testing-automation-tools/">5 Testing Automation Tools</a> in Qameta Software blog (Allure Report maintainers)</li>
<li>Selenide got to compilation <a href="https://hackernoon.com/top-java-libraries-for-automation-testing-in-2022">Top Java Libraries for Automation Testing in 2022</a></li>
<li>Post <a href="https://blog.knoldus.com/selenide-concise-ui-test-in-java/">about Selenide</a> in Knoldus blog</li>
<li>Post <a href="https://medium.com/@gaveen0513/selenide-the-software-that-doesnt-need-documentation-cda8535cb7e6">The software that doesn’t need documentation</a> by Gaveen Nayanajith</li>
<li>Post <a href="https://mszeles.com/selenide-i-think-this-is-the-beginning-of-a-beautiful-friendship">the beginning of a beautiful friendship</a> by Miklós Szeles</li>
</ul>
<p><br /></p>
<h4 id="i-think-this-is-the-beginning-of-a-beautiful-friendship">I think this is the beginning of a beautiful friendship!</h4>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.2.02022-01-10T00:00:00+00:00https://selenide.org/2022/01/10/selenide-6.2.0
<p><br /></p>
<h1 id="happy-new-year-people">Happy New Year, people!</h1>
<p><br />
We released <a href="https://github.com/selenide/selenide/milestone/140?closed=1">Selenide 6.2.0</a>.</p>
<p>Let’s look into this year’s first release.</p>
<p>Pour some tea and let’s go!</p>
<p><br /></p>
<h1 id="added-link-click-to-see-difference-for-most-of-selenide-assertion-errors">Added link “<Click to see difference>” for most of Selenide assertion errors</h1>
<p>As you remember, in <a href="/2021/09/28/selenide-5.25.0/">Selenide 5.25.0</a> we added Test4J support. As a result, Selenide
assertion errors got a link “<Click to see difference>” in IDE which allows to easily compare expected and actual
values in case of test failure.</p>
<p>At that moment we didn’t have enough time to refactor all the assertion errors, and some of them didn’t get the link. <br />
Now we added the link to all the errors.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1589">issue 1589</a> and <a href="https://github.com/selenide/selenide/pull/1676">PR 1676</a>.</p>
<p><br /></p>
<h1 id="replaced-iterator-by-asdynamiciterable-and-asfixediterable">Replaced <code class="language-plaintext highlighter-rouge">$$.iterator()</code> by <code class="language-plaintext highlighter-rouge">$$.asDynamicIterable()</code> and <code class="language-plaintext highlighter-rouge">$$.asFixedIterable()</code></h1>
<blockquote>
<p><em>Wow, what an old sore we have fixed!</em></p>
</blockquote>
<p>Selenide has method <code class="language-plaintext highlighter-rouge">$$</code> for a collection of web elements. It returns instance of class <code class="language-plaintext highlighter-rouge">ElementsCollection</code>.<br />
Initially, it should have only one method <code class="language-plaintext highlighter-rouge">$$.shouldHave(<condition>)</code>. When you want to verify the collection -
pass it the needed condition. If you didn’t find a needed condition - create your own, it’s easy.</p>
<h3 id="the-mistake">The mistake</h3>
<p>But I did a mistake at that moment. I inherited class <code class="language-plaintext highlighter-rouge">ElementsCollection</code> from <code class="language-plaintext highlighter-rouge">AbstractList<SelenideElement></code>.
I later regretted this decision many times.</p>
<p>What happened, you may ask? People started abusing the collections.</p>
<ul>
<li>For example, they wanted to iterate the collection elements (and it <em>occasionally</em> was possible because of extending <code class="language-plaintext highlighter-rouge">AbstractList</code>).</li>
<li>they expected that the collection elements will be reloaded during the iteration (because Selenide had been updating all other web elements during checks & re-tries).</li>
<li>In addition to the questionable test design, this also caused performance problems, because at every iteration step Selenide
must reload the entire collection. And it can be slow, especially if there are many elements in the collection, or the collection is being filtered: <code class="language-plaintext highlighter-rouge">$$("div").filter(visible).filterBy(text("Hello"))</code>.</li>
</ul>
<h3 id="the-dilemma">The dilemma</h3>
<p>The dilemma turned out:</p>
<ul>
<li>some people wanted Selenide to reload collection elements during the iteration (because it helps to avoid <code class="language-plaintext highlighter-rouge">StaleElementException</code> etc when the elements appear and disappear during the iteration);</li>
<li>other people didn’t want Selenide to reload the elements because it makes tests faster on big collections.</li>
</ul>
<p>Whichever option we choose, we won’t please everyone.</p>
<h3 id="the-solution">The solution</h3>
<p>Finally, we figured out how to solve this dilemma. We <strong>deprecated</strong> all these methods like <code class="language-plaintext highlighter-rouge">$$.iterator()</code> which were occasionally inherited from <code class="language-plaintext highlighter-rouge">AbstractList</code>. As a replacement, we suggest two new methods. You can choose one of them depending on your needs:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">$$.asDynamicIterable()</code> - reload the elements during the iteration. Might be slow on big collections.</li>
<li><code class="language-plaintext highlighter-rouge">$$.asFixedIterable()</code> - doesn’t reload the elements. May be faster, but will not get updates if elements appear/disappear during the iteration.</li>
</ul>
<h3 id="the-recommendation">The recommendation</h3>
<p>Which one I recommend to you, you may ask?</p>
<p>NONE!</p>
<p>In the end, let me remind that well-designed test should not have loops, ifs etc.
You must know how many elements are expected, and which properties
they are expected to have. <em>Just verify those properties.</em></p>
<p>Instead of iteration, it’s always better to create your <a href="https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/CustomCollectionConditionTest.java">custom <code class="language-plaintext highlighter-rouge">CollectionCondition</code></a>. It’s easy.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/797">issue 797</a> and <a href="https://github.com/selenide/selenide/pull/1688">PR 1688</a>.</p>
<p><br /></p>
<h1 id="fixed-softassert-to-avoid-failing-a-test">Fixed SoftAssert to avoid failing a test</h1>
<p>in a rather rare situation:</p>
<ol>
<li>when soft assert listener/rule/extension is added to a test, but</li>
<li>soft asserts are <strong>disabled</strong>, and</li>
<li>there was an assertion error raised and caught during the test execution (try/catch).</li>
</ol>
<p>It sounds like a design smell. Probably such test should be fixed. :(</p>
<p>But still, we fixed the Selenide soft assert listener. Now it doesn’t fail the test if soft assertions are disabled.</p>
<blockquote>
<p><em>Uh, well, you sometimes throw up unexpected problems, dear users … :)</em></p>
</blockquote>
<p>See <a href="https://github.com/selenide/selenide/issues/1646">issue 1646</a> and <a href="https://github.com/selenide/selenide/pull/1680">PR 1680</a>.</p>
<p><br /></p>
<h1 id="we-fixed-soft-asserts-to-include-all-the-errors">We fixed soft asserts to include all the errors</h1>
<p>There was one more rare problem with soft asserts. Image the situation:</p>
<ol>
<li>You have soft asserts enabled;</li>
<li>During the test execution, some Selenide assertion errors were raised (and caught by the listener);</li>
<li>But there was also some other assertion error (like <code class="language-plaintext highlighter-rouge">NPE</code> or <code class="language-plaintext highlighter-rouge">assertEquals(2, 3)</code>).</li>
</ol>
<p>In this case, Selenide soft assert listener failed the test (which is correct), but showed only Selenide assertion errors (#2) and lost the “other” error (#3).</p>
<p>Now the listener got smarter: it merges all the assertion errors.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1661">issue 1661</a> and <a href="https://github.com/selenide/selenide/pull/1679">PR 1679</a>.</p>
<p><br /></p>
<h1 id="we-added-locator-to-some-of-selenide-assertion-errors">We added locator to some of Selenide assertion errors</h1>
<p>Another small improvement.</p>
<p>We added a locator to some of Selenide assertion errors.<br />
For example, if previously you could see an error like this:</p>
<blockquote>
<p>“Invalid element state: Cannot change invisible element”</p>
</blockquote>
<p>then now you will see the improved error message:</p>
<blockquote>
<p>“Invalid element state [.btn.btn-primary]: Cannot change invisible element”</p>
</blockquote>
<p><br /></p>
<h1 id="upgraded-browserupproxy-from-212-to-213">Upgraded BrowserUpProxy from 2.1.2 to 2.1.3</h1>
<p>Note that version 2.1.3 is a <strong>fork</strong> of the original BrowserUpProxy.
The authors announced the end of support, and the volunteers took over and released version 2.1.3 <a href="https://github.com/browserup/browserup-proxy/issues/388#issuecomment-1004097733">from the fork</a>.</p>
<p>We will monitor the situation. Ideally, it would be great to switch from BrowserUpProxy to mitmproxy. Are there volunteers?</p>
<p>See <a href="https://github.com/selenide/selenide/pull/1678">PR 1678</a>.</p>
<p><br /></p>
<h1 id="upgraded-testng-from-740-to-75">Upgraded TestNG from 7.4.0 to 7.5</h1>
<p>Changelist is quite <a href="https://github.com/cbeust/testng/blob/7.5/CHANGES.txt">impressive</a>.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/1682">PR 1682</a>.</p>
<p><br /></p>
<p>Happy New Year, my friends!<br />
I wish you stable tests and beautiful reports!</p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.1.12021-11-24T00:00:00+00:00https://selenide.org/2021/11/24/selenide-6.1.1
<p><br /></p>
<h1 id="tere-hommikust">TERE HOMMIKUST!</h1>
<p><br />
We released <a href="https://github.com/selenide/selenide/milestone/141?closed=1">Selenide 6.1.1</a>.</p>
<p>In this tiny release we fixed a bunch of problems with browser settings.<br />
These problems arose after upgrading to Selenium 4 where <code class="language-plaintext highlighter-rouge">ChromeOptions</code> and other <code class="language-plaintext highlighter-rouge">Capabilities</code> were refactored.</p>
<p>Now we plunged into the topic and fixed all the problems at once.</p>
<p><br /></p>
<h1 id="early-conflicts-detection">Early conflict detection</h1>
<p>If you try to open a Chrome with Firefox settings:</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>then Selenide 5.x did show a clear error message, but Selenide 6.0.x didn’t.<br />
Now we have restored the swearing, and you will see the old good</p>
<blockquote>
<p>IllegalArgumentException: Conflicting browser name: ‘chrome’ vs. ‘firefox’</p>
</blockquote>
<p>See <a href="https://github.com/selenide/selenide/issues/1591">issue 1591</a> and <a href="https://github.com/selenide/selenide/pull/1642">PR 1642</a>.</p>
<p><br /></p>
<h1 id="merging-chrome-arguments">Merging of chrome arguments</h1>
<p>Say, if you want to run Chrome in full screen mode or setup its language:</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>then these settings were lost in Selenide 6.0.x<br />
Now we have restored them.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1626">issue 1626</a>,
<a href="https://github.com/selenide/selenide/issues/1630">issue 1630</a> and
<a href="https://github.com/selenide/selenide/issues/1631">issue 1631</a>.</p>
<p>The fix was in <a href="https://github.com/selenide/selenide/pull/1642">PR 1642</a>.</p>
<p><br /></p>
<h1 id="wrapping-browser-capabilities">IMPORTANT</h1>
<p>If you used <code class="language-plaintext highlighter-rouge">Configuration.browserCapabilities</code>, then with a high probability you wrapped it into <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>Now you have to <strong>simplify your code</strong>, to avoid loosing of your settings:</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">We changed the parameter type of <code class="language-plaintext highlighter-rouge">WebDriverProvider</code></h1>
<p>… from <code class="language-plaintext highlighter-rouge">DesiredCapabilities</code> to just <code class="language-plaintext highlighter-rouge">Capabilities</code>.</p>
<p>For you, almost nothing changes. If you use <code class="language-plaintext highlighter-rouge">WebDriverProvider</code> in your tests, simply
change <code class="language-plaintext highlighter-rouge">DesiredCapabilities</code> to<code class="language-plaintext highlighter-rouge"> Capabilities</code> and everything will work as previously.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/1642">PR 1642</a>.</p>
<p><br /></p>
<p><em>More capabilities for the Capabilities God!</em></p>
<p><br /></p>
<h1 id="upd-selenide-6.1.2">UPD Selenide 6.1.2</h1>
<p>We released Selenide 6.1.2 with upgrade to Selenium 4.1.1. It has several remarkable bugfixes.</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.1.02021-11-23T00:00:00+00:00https://selenide.org/2021/11/23/selenide-6.1.0
<p><br /></p>
<h1 id="tere">TERE!</h1>
<p><br />
We released <a href="https://github.com/selenide/selenide/milestone/137?closed=1">Selenide 6.1.0</a>.</p>
<p><br /></p>
<h1 id="added-support-for-selenideproperties">Added support for <code class="language-plaintext highlighter-rouge">selenide.properties</code></h1>
<p>Now Selenide can read its settings from file <code class="language-plaintext highlighter-rouge">selenide.properties</code> if it’s found in classpath.</p>
<p>NB! I personally still don’t find it really useful. It’s easier to just set settings</p>
<ol>
<li>right in code: <code class="language-plaintext highlighter-rouge">Configuration.timeout = 8000;</code></li>
<li>or via system properties: <code class="language-plaintext highlighter-rouge">-Dselenide.timeout=8000</code>.</li>
</ol>
<p>Please, don’t rush generating these files. Use <code class="language-plaintext highlighter-rouge">selenide.properties</code> only if you have a good reason,
and not simply because it is now fashionable or “beautiful”.</p>
<p>Thanks to <a href="https://github.com/petroOv-PDFfiller">Petro Ovcharenko</a> for
<a href="https://github.com/selenide/selenide/pull/1601">PR 1601</a>.</p>
<p><br /></p>
<h1 id="added-possibility-for-fine-tuning-the-proxy">Added possibility for fine tuning the proxy</h1>
<p>As you know, Selenide can run its embedded proxy server. It makes possible downloading of files, listening/intercepting requests etc.
But capabilities of configuring the proxy were quite limited by now: only <code class="language-plaintext highlighter-rouge">Configuration.proxyHost</code> and <code class="language-plaintext highlighter-rouge">Configuration.proxyPort</code>.</p>
<p>Now you can get the instance of BrowserModProxy and set it up as you wish before opening a browser.</p>
<p>NB! Please don’t overuse it. It’s very easy to shoot yourself in the foot via re-configuring the proxy.</p>
<p>And don’t forget: if your settings really helped you, then maybe they will help others as well.
Tell us what you set up there - maybe we should make these proxy settings default in Selenide?</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1561">issue 1561</a>.
Thanks to <a href="https://github.com/BorisOsipov">Boris Osipov</a> for
<a href="https://github.com/selenide/selenide/pull/1620">PR 1620</a>.</p>
<p><br /></p>
<h1 id="added-a-workaround-against-random-noclassdeffounderror-in-webdriverexception">Added a workaround against random <code class="language-plaintext highlighter-rouge">NoClassDefFoundError</code> in <code class="language-plaintext highlighter-rouge">WebDriverException</code>.</h1>
<p>There is <a href="https://github.com/SeleniumHQ/selenium/issues/9784">a bug in Selenium</a> which is not entirely fixed yet.
But you will not see it anymore because we added a workaround in Selenide code. :)</p>
<p>See <a href="https://github.com/selenide/selenide/commit/2eff0307e3a">the workaround</a>.</p>
<p><br /></p>
<h1 id="changed-parameter-type-for-method-selenideconfigbrowsercapabilities">Changed parameter type for method <code class="language-plaintext highlighter-rouge">SelenideConfig.browserCapabilities()</code></h1>
<p>… from <code class="language-plaintext highlighter-rouge">DesiredCapabilities</code> to <code class="language-plaintext highlighter-rouge">MutableCapabilities</code>.</p>
<p>It allows to simplify your code. You don’t need to wrap <code class="language-plaintext highlighter-rouge">ChromeOptions</code> into <code class="language-plaintext highlighter-rouge">DesiredCapabilities</code> anymore.
More about simplification of capabilities will be in the next release <code class="language-plaintext highlighter-rouge">Selenide 6.1.1</code>.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/1637">PR 1637</a>.</p>
<p><br /></p>
<h1 id="upgraded-to-selenium-webdriver-410">Upgraded to Selenium Webdriver 4.1.0</h1>
<p>Thanks to <a href="https://github.com/BorisOsipov">Boris Osipov</a> for <a href="https://github.com/selenide/selenide/pull/1638">PR 1638</a>.</p>
<p><br /></p>
<h1 id="removed-method-shadowroot">Removed method <code class="language-plaintext highlighter-rouge">$.shadowRoot()</code></h1>
<p>This method got broken after upgrading to Chrome 96, and probably will be broken in other browsers soon.<br />
Taking into account that</p>
<ol>
<li>It’s hard to fix this method, and</li>
<li>This method <a href="https://github.com/selenide/selenide/issues/1515#issuecomment-894476289">is not really useful</a> since there are <a href="/2020/03/18/selenide-5.10.0/">better ways</a> to find elements in Shadow DOM.
we decided to just delete this method. Easy! :)</li>
</ol>
<p>See <a href="https://github.com/selenide/selenide/issues/1640">issue 1640</a> and
<a href="https://github.com/selenide/selenide/pull/1641">PR 1641</a>.</p>
<p><br /></p>
<h1 id="news">News</h1>
<ul>
<li>A <a href="https://www.linkedin.com/posts/qametasoftware_propeller-testops-hackathon-activity-6869263215520550912-m2_-/">QA/TestOps Hackaton</a> by PropellerAds and Qameta Software. Register!</li>
<li><a href="https://www.lambdatest.com/selenium-automation-testing-with-selenide-framework">How to use Selenide with Lambdatest service</a></li>
<li>A post <a href="https://mbbaig.blog/selenide-webdriverfactory/">Selenide - Create a Custom WebDriver</a> by Boris Bay</li>
<li>Wow! <a href="https://www.linkedin.com/feed/update/urn:li:activity:6867477909766979584/">LinkedIn runs course on Selenide</a> and even gives nice diplomas! :)</li>
</ul>
<p><br /></p>
<h1 id="selenide-downloads-statistics">Selenide downloads statistics</h1>
<center>
<img src="/images/2021/11/selenide.downloads.png" width="800" />
</center>
<p><br />
In October we made a big leap and exceeded <strong>280 thousand downloads</strong> per month.</p>
<p><em>More downloads for the Downloads God!</em></p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 6.0.12021-10-25T00:00:00+00:00https://selenide.org/2021/10/25/selenide-6.0.1
<p><br /></p>
<h1 id="happy-birthday-selenide">Happy Birthday, Selenide!</h1>
<p>Wow! It’s hard to believe, but today Selenide got … 10 years old!</p>
<p>This day 10 years ago was created <a href="https://github.com/selenide/selenide/commit/3716078fc7fda8c5da01d871882d513cbd97cd0e">the first commit</a> to Selenide github repository.</p>
<p>Many thanks to everyone who participated in the project, committed, reported bugs, suggested ideas, answered questions in the forums,
criticized and talked about selenide at conferences and meetups. And who just decided to use Selenide in their projects.
You are all part of this movement.</p>
<p><br />
In honor of the anniversary, we released major version <a href="https://github.com/selenide/selenide/milestone/136?closed=1">Selenide 6.0.1</a>.</p>
<p><br /></p>
<h1 id="upgraded-to-selenium-webdriver-400">Upgraded to Selenium Webdriver 4.0.0</h1>
<p>Nothing really should change for you until you are using Selenium Grid. Everything more or less works as before.
Well, some classes were renamed or deprecated - it seems not scary.</p>
<p>Selenium 4 also brings <a href="https://www.browserstack.com/guide/selenium-4-features">new features</a> (like CDP and Relative locators), but haven’t introduced any special support for them yet. Can work on it in next versions if needed.</p>
<p>See <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> and
<a href="https://github.com/selenide/selenide/pull/1617">PR 1617</a>.</p>
<p><br /></p>
<h1 id="splitted-selenide-to-several-artifacts">Splitted Selenide to several artifacts</h1>
<p>Before now, the whole Selenide code was published as a single artifact: <code class="language-plaintext highlighter-rouge">selenide-5.25.0.jar</code>.<br />
And you had to add other dependencies like JUnit or TestNG, and probably BrowserMobProxy.</p>
<p>Now we made it easier for you (especially with proxy).</p>
<ol>
<li>For JUnit5 users the dependency will not change: <br /><code class="language-plaintext highlighter-rouge">testImplementation("com.codeborne:selenide:6.0.1)</code></li>
<li>JUnit4 users should use <br /> <code class="language-plaintext highlighter-rouge">testImplementation("com.codeborne:selenide-junit4:6.0.1)</code></li>
<li>TestNG users should use <br /> <code class="language-plaintext highlighter-rouge">testImplementation("com.codeborne:selenide-testng:6.0.1)</code></li>
<li>If you want to use proxy, it’s enough to add dependency <br /> <code class="language-plaintext highlighter-rouge">testImplementation("com.codeborne:selenide-proxy:6.0.1)</code> - and forget about all these BrowserUpProxy, Netty etc.</li>
<li>And if you happen to be a radical hater of static methods, now you can also be happy by declaring <br /> <code class="language-plaintext highlighter-rouge">testImplementation("com.codeborne:selenide-core:6.0.1)</code> - and then you will only have <code class="language-plaintext highlighter-rouge">SelenideDriver</code> without <code class="language-plaintext highlighter-rouge">Selenide.*</code> static methods.</li>
</ol>
<p>See <a href="https://github.com/selenide/selenide/pull/1612">PR 1612</a>.</p>
<p><br /></p>
<h1 id="removed-lots-of-deprecated-code">Removed lots of deprecated code</h1>
<p><a href="https://github.com/selenide/selenide/pull/1607/files">Here</a> you can find what exactly was removed and how can you replaced it. <br />
In particular,</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">ElementsCollection.shouldHaveSize()</code> -> <code class="language-plaintext highlighter-rouge">ElementsCollection.shouldHave(size())</code></li>
<li><code class="language-plaintext highlighter-rouge">$.waitUntil(_, timeout)</code> -> <code class="language-plaintext highlighter-rouge">$.should(_, Duration.ofMillis(timeout))</code></li>
<li><code class="language-plaintext highlighter-rouge">$.waitWhile(_, timeout)</code> -> <code class="language-plaintext highlighter-rouge">$.shouldNot(_, Duration.ofMillis(timeout))</code></li>
<li><code class="language-plaintext highlighter-rouge">Condition.disappears</code> -> <code class="language-plaintext highlighter-rouge">Condition.hidden</code></li>
<li><code class="language-plaintext highlighter-rouge">Condition.matchesText</code> -> <code class="language-plaintext highlighter-rouge">Condition.matchText</code></li>
<li><code class="language-plaintext highlighter-rouge">Selenide.close</code> -> <code class="language-plaintext highlighter-rouge">Selenide.closeWebDriver()</code> or <code class="language-plaintext highlighter-rouge">Selenide.closeWindow()</code>
<br /></li>
</ul>
<p>Thanks to <a href="https://github.com/BorisOsipov">Boris Osipov</a> for
<a href="https://github.com/selenide/selenide/pull/1607/files">PR 1607</a> and
<a href="https://github.com/selenide/selenide/pull/1609">PR 1609</a>.</p>
<p><br /></p>
<h1 id="remove-support-for-browser-legacy_firefox">Remove support for browser “legacy_firefox”</h1>
<p>It was an old webdriver that worked with Firefox 52 and earlier. I guess it’s not used anymore.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/1610">PR 1610</a>.</p>
<p><br /></p>
<h1 id="removed-some-old-settings">Removed some old settings</h1>
<h3 id="configurationstartmaximized"><code class="language-plaintext highlighter-rouge">Configuration.startMaximized</code></h3>
<p>We think this is bad practice, because the size of the browser window depends on the current environment, which can lead to flaky tests.
We recommend to use <code class="language-plaintext highlighter-rouge">Configuration.browserSize</code> instead (default value is <code class="language-plaintext highlighter-rouge">1366x768</code>).</p>
<h3 id="configurationversatilesetvalue"><code class="language-plaintext highlighter-rouge">Configuration.versatileSetValue</code></h3>
<p>Most probably you didn’t use it because it was <code class="language-plaintext highlighter-rouge">false</code> by default. <br />
Now for selecting a value from <code class="language-plaintext highlighter-rouge"><select></code> or <code class="language-plaintext highlighter-rouge"><input type=radio></code> you can use plain old methods <code class="language-plaintext highlighter-rouge">$.selectOptionByValue()</code> and <code class="language-plaintext highlighter-rouge">$.selectRadio()</code>.</p>
<p>Thanks to <a href="https://github.com/BorisOsipov">Boris Osipov</a> for <a href="https://github.com/selenide/selenide/pull/1619">PR 1619</a>.</p>
<p><br /></p>
<h1 id="fixed-method-selenidesleepn">Fixed method <code class="language-plaintext highlighter-rouge">Selenide.sleep(N)</code></h1>
<p>It turns out that the standard Java method <code class="language-plaintext highlighter-rouge">Thread.sleep (N)</code> does not necessarily sleep exactly N ms, it can wake up earlier.
And this can cause flaky tests if your expected a certain pause.</p>
<p>Now method <code class="language-plaintext highlighter-rouge">Selenide.sleep(N)</code> is guaranteed to wait at least given number of milliseconds.</p>
<p>See <a href="https://github.com/selenide/selenide/blob/b05d53dfb794ee02e795587867c6ec8022171040/statics/src/main/java/com/codeborne/selenide/Selenide.java#L258">implementation</a>.</p>
<p><br /></p>
<h1 id="added-methods-for-addingremoving-webdriverlistener">Added methods for adding/removing <code class="language-plaintext highlighter-rouge">WebDriverListener</code></h1>
<p>Selenide has method for adding <code class="language-plaintext highlighter-rouge">WebDriverEventListener</code>, but this class was replaced by <code class="language-plaintext highlighter-rouge">WebDriverListener</code> in Selenium 4. <br />
So we have to support both.</p>
<p><br /></p>
<p>See <a href="https://github.com/selenide/selenide/issues/1615">issue 1615</a> and <a href="https://github.com/selenide/selenide/pull/1616">PR 1616</a>.</p>
<p><br /></p>
<h1 id="changed-signature-of-method-conditionapply">Changed signature of method <code class="language-plaintext highlighter-rouge">Condition.apply</code></h1>
<p>It doesn’t concern you until you created your custom Conditions.</p>
<p>Before now, class <code class="language-plaintext highlighter-rouge">Condition</code> had method <code class="language-plaintext highlighter-rouge">apply</code> which returned <code class="language-plaintext highlighter-rouge">boolean</code>:</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>Now you need to rename it to <code class="language-plaintext highlighter-rouge">check</code> and return <code class="language-plaintext highlighter-rouge">CheckResult</code> instead of <code class="language-plaintext highlighter-rouge">boolean</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>This <code class="language-plaintext highlighter-rouge">CheckResult</code> contains not only flag “condition met / not met”, but also a actual value at that moment. <br />
It allows Selenide to generate a better error message in case of test failure.</p>
<p>P.S. Though, old method <code class="language-plaintext highlighter-rouge">apply</code> is not removed, but just marked as deprecated. So you can postpone this refactoring for some time.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/217">issue 217</a>,
<a href="https://github.com/selenide/selenide/pull/1586">PR 1586</a> and
<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>We released <a href="https://github.com/selenide/selenide-selenoid/releases/tag/v2.0.1"><code class="language-plaintext highlighter-rouge">selenide-selenoid:2.0.1</code></a> with upgrade to Selenide 6.0.1</p>
<p><br /></p>
<h1 id="selenide-appium">selenide-appium</h1>
<p>It seems that Appium doesn’t support Selenium 4 yet, so we cannot upgrade <code class="language-plaintext highlighter-rouge">selenide-appium</code> yet. Stay tuned.</p>
<p><br /></p>
<h1 id="upd-selenide-602">UPD Selenide 6.0.2</h1>
<p>We found a problem with projects using TestNG, released a hotfix 6.0.2.</p>
<p>See <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>It appears that Maven can fetch an older version of <code class="language-plaintext highlighter-rouge">selenium-api-3*.jar</code> if it’s found in a dependency tree (usually in BrowserUpProxy or Allure transitive dependencies).</p>
<p>I personally find this Maven behaviour misleading and just wrong. Maven could pick up a newer version.<br />
But since people often experience this problem, we decided to add a workaround on Selenide side.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/1625">workaround 1625</a></p>
<p><br /></p>
<h1 id="what-to-read-about-selenium-4">What to read about 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/">Updated Selenium website</a></li>
</ul>
<p><br /></p>
<h1 id="other-news">Other news</h1>
<ul>
<li>Aerokube released <a href="https://github.com/aerokube/lightning-java">alternative WebDriver client</a>. In theory, Selenide could now use it under the hood instead of Selenium Webdriver. Sounds tempting?</li>
<li>I haven’t figured it out yet, but people seem to be praising it: <a href="https://github.com/markhobson/docker-maven-chrome">some Docker images for Selenium</a></li>
</ul>
<p><br /></p>
<h1 id="selenide-download-statistics">Selenide download statistics</h1>
<center>
<img src="/images/2021/10/selenide.downloads.png" width="800" />
</center>
<p><br />
We crossed <strong>255K downloads</strong> per months!</p>
<p>What is waiting us in next 10 years?</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.25.02021-09-28T00:00:00+00:00https://selenide.org/2021/09/28/selenide-5.25.0
<p>Good evening!</p>
<p>We released <a href="https://github.com/selenide/selenide/milestone/131?closed=1">Selenide 5.25.0</a>.</p>
<blockquote>
<p><strong>I strongly recommend you to upgrade</strong>,<br />
because there are even more changes coming with next releases, including the full release of Selenium 4.<br />
If you don’t upgrade now, it will be much more difficult to clear the rubble later!</p>
</blockquote>
<p>This is quite a big release with a bunch of changes, so grab some popcorn and make some tea. Let’s go!</p>
<ul>
<li><a href="#support-webdriver-4.0.0.RC1">Support for Selenium Webdriver 4.0.0 RC1</a></li>
<li><a href="#opentest4j">Support for OpenTest4j</a></li>
<li><a href="#stacktrace-in-soft-asserts">Stacktrace below every error in soft asserts</a></li>
<li><a href="#get-shadow-root">Added method <code class="language-plaintext highlighter-rouge">$.shadowRoot()</code></a></li>
<li><a href="#get-ancestor">Added method <code class="language-plaintext highlighter-rouge">$.ancestor()</code></a></li>
<li><a href="#enrich-ancestor">Enriched methods <code class="language-plaintext highlighter-rouge">$.closest()</code> and <code class="language-plaintext highlighter-rouge">$.ancestor()</code></a></li>
<li><a href="#fixed-element-screenshot">Fixed method <code class="language-plaintext highlighter-rouge">$.screenshot()</code> on Mac</a></li>
<li><a href="#actual-value-at-the-moment-of-last-check">Now Selenide reports an exact text at the moment of test failure</a></li>
<li><a href="#empty-text-not-allowed">We now forbid an empty argument in method <code class="language-plaintext highlighter-rouge">$.matchText("")</code></a></li>
<li><a href="#check-webdriver-title">Check <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="#statistics">Selenide downloads statistics</a></li>
<li><a href="#selenide-anniversary">Selenide anniversary</a></li>
</ul>
<p><br /></p>
<h1 id="support-webdriver-4.0.0.RC1">Support for Selenium Webdriver 4.0.0 RC1</h1>
<p>We released two builds of Selenide 5.25.0: regular and hipster one. <br />
You can pick:</p>
<table>
<tbody>
<tr>
<td>either</td>
<td><code class="language-plaintext highlighter-rouge">com.codeborne:selenide:5.25.0</code></td>
<td>(with <code class="language-plaintext highlighter-rouge">Selenium 3.x</code>),</td>
</tr>
<tr>
<td>or</td>
<td><code class="language-plaintext highlighter-rouge">com.codeborne:selenide:5.25.0-selenium-4.0.0-rc-1</code></td>
<td>(with <code class="language-plaintext highlighter-rouge">Selenium 4.0.0 RC1</code>).</td>
</tr>
</tbody>
</table>
<p><br /></p>
<h1 id="opentest4j">We added support for OpenTest4j</h1>
<p>If you haven’t heard yet, <a href="https://github.com/ota4j-team/opentest4j">OpenTest4j</a> is a small library for
assertion errors created by JUnit 5 team. The idea is that:</p>
<ul>
<li>all testing frameworks should throw these errors, and</li>
<li>all IDEs should support them.</li>
</ul>
<p>Yet another standard, like webdriver. :)
All major players like JUnit, TestNG, AssertJ, IDEA and Eclipse already supported opentest4j, and now does Selenide too.</p>
<p><strong>What will change for you personally:</strong><br />
When your UI fails (well, <a href="https://github.com/selenide/selenide/issues/1589">almost always</a>), IDEA will show a nice
link <code class="language-plaintext highlighter-rouge"><Click to see difference></code> below. By clicking it you can view a nice DIFF in a separate IDEA dialog.
Very convenient for debugging.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/969">issue 969</a> and <a href="https://github.com/selenide/selenide/pull/1545">PR 1545</a>.</p>
<p>NB! If you use directly some of Selenide assertion errors (inherit or throw), you will need to update your code a bit.<br />
We slightly change signature of their constructors:</p>
<ul>
<li>flipped “expected” and “actual” arguments</li>
<li>removed unneeded “driver” argument from most constructors</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">Now we show stacktrace below every error in soft asserts</h1>
<p>Until now, Selenide soft asserts showed only one stack trace in the end of all errors. It allows to keep the
total error message (relatively) short.<br />
But in practice it’s convenient to see a separate stacktrace for every error. It allows to quickly click the needed line
and get to the right place in the code.</p>
<p>Now you will see separate under every error. I personally don’t like that the error message has become much longer,
but usually there shouldn’t be too many of errors, right? ;)</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1543">issue 1543</a> and <a href="https://github.com/selenide/selenide/pull/1545">PR 1545</a></p>
<p><br /></p>
<h1 id="get-shadow-root">We added method <code class="language-plaintext highlighter-rouge">$.shadowRoot()</code></h1>
<p>Until now, you could only search elements <em>inside of</em> shadow root, and now you can get the shadow root itself.<br />
Though, there is still little benefit from this because search within this element is not supported
(by browsers or web drivers, I am not sure).</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1515">issue 1515</a> and <a href="https://github.com/selenide/selenide/pull/1517">PR 1517</a>.</p>
<p><br /></p>
<h1 id="get-ancestor">We added method <code class="language-plaintext highlighter-rouge">$.ancestor()</code></h1>
<p>It’s an alias for existing method <code class="language-plaintext highlighter-rouge">$.closest()</code>. The name <code class="language-plaintext highlighter-rouge">closest</code> was originally from JQuery (which is old!),
while <code class="language-plaintext highlighter-rouge">ancestor</code> should be more clear because it’s a standard XPath term.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1556">issue 1556</a>.<br />
Thanks to <a href="https://github.com/bereg2k">Oleg Berezhnoy</a> for <a href="https://github.com/selenide/selenide/pull/1567">PR 1567</a>.</p>
<p><br /></p>
<h1 id="enrich-ancestor">We enriched methods <code class="language-plaintext highlighter-rouge">$.closest()</code> and <code class="language-plaintext highlighter-rouge">$.ancestor()</code></h1>
<p>Until now, this method could only search element by tag or class name:</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>Now it can search by attributes:</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>Thanks to <a href="https://github.com/plagov">Vitali Plagov</a> for <a href="https://github.com/selenide/selenide/pull/1554">PR 1554</a></p>
<p><br /></p>
<h1 id="fixed-element-screenshot">We fixed method <code class="language-plaintext highlighter-rouge">$.screenshot()</code> on Mac</h1>
<p>For a long time, Selenide has method <code class="language-plaintext highlighter-rouge">$.screenshot()</code> to take screenshot of some element (instead of a full screen).<br />
We found that this method worked incorrectly on MacBooks because of Retina display.</p>
<p>Now we remove the incorrect custom code from Selenide and started using a standard webdriver method that was created meanwhile.
We checked it works in at least Chrome, Firefox and Edge.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1571">issue 1571</a> and <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">Now Selenide reports an exact text at the moment of test failure</h1>
<p>Wow, what old issues we sometimes fix! This ticket was registered already on <em>September 6, 2015</em>!</p>
<p><strong>In general, the story is like this.</strong></p>
<p>Let’s assume you have a check in test:</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>And a standard timeout 4 seconds. Here is one possible scenario:</p>
<ol>
<li>during 4 seconds, Selenide checks the element text, but it’s wrong all the time (say, “Goodbye”).</li>
<li>timeout expires,</li>
<li>selenide decides to throw an assertion error,</li>
<li>composes an error message, including actual element text.</li>
<li>at this moment the element text changes. Say, to “Hello”.</li>
</ol>
<p>It happens very rarely, but when it happens, it may confuse a lot.<br />
You are seeing an error message and feel totally confused:</p>
<blockquote>
<p>Text didn’t match. Expected text: “Hello”, actual text: “Hello”.</p>
</blockquote>
<p>Now Selenide remembers <strong>exactly the text</strong> at the moment of last check and appends it to the error message.</p>
<p>P.S. In next releases, we are going to improve this mechanism even more. We will show the history of element texts
during those unfortunate 4 seconds. It may help debugging some tricky cases with flaky tests etc.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/217">issue 217</a> and <a href="https://github.com/selenide/selenide/pull/1566">PR 1566</a>.<br />
Thanks to <a href="https://github.com/fokinp">Pavel Fokin</a> for <a href="https://github.com/selenide/selenide/pull/1313">PR 1313</a>.</p>
<p><br /></p>
<h1 id="empty-text-not-allowed">We now forbid an empty argument in method <code class="language-plaintext highlighter-rouge">$.matchText("")</code></h1>
<p>There is a method for checking element text with a regular expression:</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">"Tallin{1,2}"</span><span class="o">)));</span>
</code></pre></div></div>
<p>We found that it was possible to occasionally pass an empty string to <code class="language-plaintext highlighter-rouge">matchText</code> which might cause false-positive tests.<br />
Now you will see an exception when trying to execute <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>See <a href="https://github.com/selenide/selenide/pull/1566/commits/3f6421226c">PR 1566</a></p>
<p><br /></p>
<h1 id="check-webdriver-title">We added check <code class="language-plaintext highlighter-rouge">webdriver().shouldHave(title(...))</code></h1>
<p>As usually, you can use it with default or custom timeout:</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>See <a href="https://github.com/selenide/selenide/issues/1573">issue 1573</a>.<br />
Thanks to <a href="https://github.com/ervuks">Ervīns Patmalnieks</a> for <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>We released <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>
with upgrade to Selenide 5.25.0.</p>
<p><br /></p>
<h1 id="release-selenide-appium-1.7.0">selenide-appium 1.7.0</h1>
<p>We released <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>
with upgrade to Selenide 5.25.0.</p>
<p><br /></p>
<h1 id="statistics">Selenide downloads statistics</h1>
<center>
<img src="/images/2021/09/selenide.downloads.png" width="800" />
</center>
<p><br />
The milestone has been passed: we exceeded <strong>250 thousand downloads</strong> per month.</p>
<p><br /></p>
<h2 id="selenide-anniversary">Selenide anniversary</h2>
<p>By the way, we have come close to another significant milestone: in October, Selenide will be … 10 years old!<br />
It’s hard to believe, but <a href="https://github.com/selenide/selenide/commit/3716078fc7fda8c5da01d871882d513cbd97cd0e">the first commit</a>
was made in the repository on October 25, 2011. Just look how ridiculous it was! :)</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.24.02021-08-29T00:00:00+00:00https://selenide.org/2021/08/29/selenide-5.24.0
<p>On August 29, 1997 a computer system Skynet became self-aware and launched nuclear missiles at Russia.
So the war between humans and terminators began.</p>
<p>It happened .. oh, my god! - 24 years ago. We live in the Future, and we are still alive. And we still rule the machines.</p>
<p>I
I celebrate this day every year, and today, in honor of the holiday, we released <a href="https://github.com/selenide/selenide/milestone/130?closed=1">Selenide 5.24.0</a>.</p>
<p><br /></p>
<h1 id="we-added-method-executecommand-duration">We added method <code class="language-plaintext highlighter-rouge">$.execute(Command, Duration)</code></h1>
<p>to run custom commands with a custom timeout.</p>
<p>In <a href="https://ru.selenide.org/2019/09/02/selenide-5.3.0/">Selenide 5.3.0</a> we added method <code class="language-plaintext highlighter-rouge">$.execute()</code> for running custom commands.
But it could only use a default timeout. Now you can use custom timeout for any custom command.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1525">issue 1525</a>.<br />
Thanks to <a href="https://github.com/evpl">Evgenii Plugatar</a> for <a href="https://github.com/selenide/selenide/pull/1531">PR 1531</a>.</p>
<p><br /></p>
<h1 id="methods-executecommand-and-executecommand-duration-dont-pass-arguments-to-the-command">Methods <code class="language-plaintext highlighter-rouge">$.execute(Command)</code> and <code class="language-plaintext highlighter-rouge">$.execute(Command, Duration)</code> don’t pass arguments to the command</h1>
<p>It’s a small change, but it might break your custom commands if you have some. Be prepared.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1527">issue 1527</a>.<br />
Thanks to <a href="https://github.com/evpl">Evgenii Plugatar</a> for <a href="https://github.com/selenide/selenide/pull/1535">PR 1535</a>.</p>
<p><br /></p>
<h1 id="we-fixed-or-and-and-conditions-in-case-if-element-is-not-found">We fixed <code class="language-plaintext highlighter-rouge">Or</code> and <code class="language-plaintext highlighter-rouge">And</code> conditions in case if element is not found</h1>
<p>See <a href="https://github.com/selenide/selenide/issues/1534">issue 1534</a>.<br />
Thanks to <a href="https://github.com/evpl">Evgenii Plugatar</a> for <a href="https://github.com/selenide/selenide/pull/1539">PR 1539</a>.</p>
<p><br /></p>
<h1 id="now-or-and-and-dont-accept-empty-conditions-list">Now <code class="language-plaintext highlighter-rouge">Or</code> and <code class="language-plaintext highlighter-rouge">And</code> don’t accept empty conditions list</h1>
<p>I hope you never tried to use <code class="language-plaintext highlighter-rouge">Or</code> and <code class="language-plaintext highlighter-rouge">And</code> with an empty conditions list because it makes no sense. Anyway, now you will get a runtime exception if you try to. <br />
Thanks to <a href="https://github.com/evpl">Evgenii Plugatar</a> for <a href="https://github.com/selenide/selenide/pull/1542">PR 1542</a>.</p>
<p><br /></p>
<h1 id="we-renamed-methods-conditionapplynull-and-collectionconditionapplynull">We renamed methods <code class="language-plaintext highlighter-rouge">Condition.applyNull()</code> and <code class="language-plaintext highlighter-rouge">CollectionCondition.applyNull()</code></h1>
<p>Many years ago I named it <code class="language-plaintext highlighter-rouge">applyNull</code>, but this name is very misleading.<br />
This method checks if the condition is met if the element is not found at all. Now it’s named <code class="language-plaintext highlighter-rouge">missingElementSatisfiesCondition()</code> - a rather long, but accurate.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1541">issue 1541</a>.<br />
Thanks to <a href="https://github.com/evpl">Evgenii Plugatar</a> for <a href="https://github.com/selenide/selenide/pull/1544">PR 1544</a>.</p>
<p><br /></p>
<h1 id="we-removed-useless-stacktraces-when-closing-the-webdriver">We removed useless stacktraces when closing the webdriver</h1>
<p>As you know, Selenide automatically closes the webdriver when it’s not needed anymore.
To make it possible, Selenide runs a few background threads which monitor the webdriver status. And sometimes these
threads compete with each other and try to close the webdriver which has been already closed by another thread.
You might see such stacktraces in your logs.</p>
<p>Now Selenide detects such situation better and doesn’t print long useless stacktraces.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1467">issue 1467</a> and
<a href="https://github.com/selenide/selenide/pull/1540">PR 1540</a></p>
<p><br /></p>
<h1 id="we-fixed-searching-shadow-roots-inside-of-web-elements">We fixed searching shadow roots inside of web elements</h1>
<p>See <a href="https://github.com/selenide/selenide/issues/1532">issue 1532</a> and
<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>We released <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> with upgrade to Selenide 5.24.0</p>
<p><br /></p>
<h1 id="selenide-appium-168">selenide-appium 1.6.8</h1>
<p>We released <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> with upgrade to Selenide 5.24.0</p>
<p><br />
<br /></p>
<h1 id="upd-selenide-5241">UPD: Selenide 5.24.1</h1>
<p>WebDriverManager is a library (used by Selenide) for downloading webdriver binaries.
They recently released a major update 5.0.0 with lots of new features. We haven’t incorporated these new features in
Selenide yet, but at least we released <strong>Selenide 5.24.1</strong> with upgrade to WebDriverManager 5.0.1.</p>
<p>Thanks to <a href="https://github.com/anilreddy">Anil Kumar Reddy Gaddam</a> for <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>We found that <code class="language-plaintext highlighter-rouge">commons-lang3</code> dependency (used by Selenide) doesn’t come transitively from WDM 5.x anymore.
We had to add it explicitly and release <strong>Selenide 5.24.2</strong>.</p>
<p>See <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>We upgraded to WebDriverManager 5.0.2, now we could exclude <code class="language-plaintext highlighter-rouge">docker-java</code> and few other dependencies.</p>
<p><br /></p>
<h1 id="upd-selenide-5244">UPD: Selenide 5.24.4</h1>
<p>We upgraded to WebDriverManager 5.0.3 which had a quickfix for the latest Firefox 92.0 on MacOS.</p>
<p><br />
<br /></p>
<h1 id="news">News</h1>
<p>The World doesn’t consist of only Web and Mobile!<br />
You can also use Selenide for testing Swing applications! Here is <a href="https://github.com/framebassman/fest-selenide">an example</a>.<br />
Under the hood it uses <a href="https://github.com/jalian-systems/marathonv5">webdriver implementation for swing</a>.</p>
<p><br /></p>
<h1 id="selenide-usage-statistics">Selenide usage statistics</h1>
<center>
<img src="/images/2021/08/selenide.downloads.png" width="800" />
</center>
<p>249+ thousands of downloads per month. We almost got 250K!</p>
<h3 id="hasta-la-vista-baby">Hasta la vista, baby!</h3>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.23.02021-07-16T00:00:00+00:00https://selenide.org/2021/07/16/selenide-5.23.0
<p>Good summer day!</p>
<p>We released <a href="https://github.com/selenide/selenide/milestone/125?closed=1">Selenide 5.23.0</a> on July, 16.</p>
<p>It introduces a fundamentally new feature in Selenide:</p>
<h1 id="the-new-generation-checks">The new generation checks</h1>
<p>Now Selenide has checks not only for <em>web</em> elements, but for some other elements too.
You can apply those checks with built-in waitings, readable error messages, reports etc. Everything you like.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1442">issue 1442</a>.
Thanks to <a href="https://github.com/dbudim">Dmitriy Budim</a> for launching this whole epic in <a href="https://github.com/selenide/selenide/pull/1478">PR 1478</a>.</p>
<p><br />
Let’s look at these checks.</p>
<h2 id="checks-for-url">Checks for URL</h2>
<p>Until now, there were 2 methods in Selenide to get an URL of a current page or frame (in most cases it’s the same value).</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>Though, it was not clear how to check them or wait for a right url.</p>
<p>Now we have such checks:</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>Every of these checks:</p>
<ol>
<li>waits up to 4 seconds (by default) if needed</li>
<li>appears in a report (text report or Allure)</li>
<li>takes a screenshot and throws a readable <code class="language-plaintext highlighter-rouge">ConditionNotMetException</code> if the url is not as expected after 4 seconds.</li>
</ol>
<p>In the best traditions of selenide, you can</p>
<ul>
<li>override the default timeout (4 seconds) to any other number, e.g. <code class="language-plaintext highlighter-rouge">Configuration.timeout = 8000;</code></li>
<li>set a custom timeout for every check (as a second parameter like <code class="language-plaintext highlighter-rouge">Duration.ofSeconds(42)</code>)</li>
<li>create custom checks (see <a href="https://github.com/selenide/selenide/blob/c045579f243fb3a5abb99033e440cf8f12caa99c/statics/src/test/java/integration/WebDriverConditionsTest.java#L127">example</a>)</li>
</ul>
<h2 id="checks-for-clipboard">Checks for clipboard</h2>
<p>Starting from version 5.20.0, Selenide has a method for accessing the clipboard:</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>But you could only get or set text to the clipboard:</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>Now you can also check the clipboard content. Again, with automated screenshots, reports, etc.</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>See <a href="https://github.com/selenide/selenide/pull/1507">PR 1507</a></p>
<h2 id="checks-for-localstorage">Checks for <code class="language-plaintext highlighter-rouge">localStorage</code></h2>
<p>Starting from version 5.15.0, Selenide has method <code class="language-plaintext highlighter-rouge">localStorage()</code> which return JavaScript object <code class="language-plaintext highlighter-rouge">LocalStorage</code>.<br />
But it had only methods <code class="language-plaintext highlighter-rouge">getItem</code> and <code class="language-plaintext highlighter-rouge">setItem</code>. Again, it was not clear how to check them or wait for an item in the local storage.</p>
<p>Now it’s clear:</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>By the way, we also added method <code class="language-plaintext highlighter-rouge">localStorage.getItems()</code> returning all the content of <code class="language-plaintext highlighter-rouge">localStorage</code> as a map.</p>
<p>See <a href="https://github.com/selenide/selenide/blob/c045579f243fb3a5abb99033e440cf8f12caa99c/statics/src/test/java/integration/LocalStorageTest.java#L157">example of custom condition</a> in Selenide tests.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/1502">PR 1502</a></p>
<h2 id="checks-for-sessionstorage">Checks for <code class="language-plaintext highlighter-rouge">sessionStorage</code></h2>
<p>The same as for <code class="language-plaintext highlighter-rouge">localStorage</code> - we added methods</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<String, String> items = sessionStorage.getItems();</code></li>
</ul>
<p>See <a href="https://github.com/selenide/selenide/pull/1502">PR 1502</a></p>
<p><br /></p>
<h1 id="a-small-refactoring">A small refactoring</h1>
<p>We made classes <code class="language-plaintext highlighter-rouge">StaticConfig</code> and <code class="language-plaintext highlighter-rouge">StaticDriver</code> non-public.<br />
It seems they shouldn’t be needed outside of Selenide.
Do you occasionally use them in your project? Contact us if you are sure you need them.</p>
<h1 id="and-a-small-bugfix">And a small bugfix:</h1>
<p>Now method <code class="language-plaintext highlighter-rouge">Selenide.screenshot("filename")</code> (again) takes a screenshot even if setting <code class="language-plaintext highlighter-rouge">Configuration.screenshots</code> is <code class="language-plaintext highlighter-rouge">false</code>.</p>
<p>Let me clarify.</p>
<ol>
<li>You can set <code class="language-plaintext highlighter-rouge">Configuration.screenshots</code> to <code class="language-plaintext highlighter-rouge">false</code> if you need to disable <em>automated</em> screenshots in case of test failures (actually, I don’t really see any reasons to do that).</li>
<li>You can use method <code class="language-plaintext highlighter-rouge">Selenide.screenshot("filename")</code> to take a screenshot at any moment you wish. Independently if the test status (I also don’t really see any reasons to do that:))</li>
</ol>
<p>The point is that method #2 works independently of setting #1. Now you can disable the automated screenshots and only take screenshots explicitly where needed (though, I still don’t see any reasons why it should be a good idea).</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1477">issue 1477</a> and <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>We released <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> with upgrade to Selenide 5.23.0</p>
<p><br /></p>
<h1 id="selenide-appium-167">selenide-appium 1.6.7</h1>
<p>We released <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> with upgrade to Selenide 5.23.0</p>
<p><br /></p>
<h1 id="new-links">New links</h1>
<ul>
<li>Post <a href="https://anilkulkarni.com/2020/03/selenide-ui-tests-in-minutes/">Selenide – UI tests in minutes</a> by Anil Kulkarni</li>
</ul>
<p><br /></p>
<h1 id="statistics">Statistics</h1>
<center>
<img src="/images/2021/07/selenide.downloads.png" width="800" />
</center>
<p>We crossed the line 232+ thousands of downloads per month!</p>
<h3 id="have-a-carefree-summer">Have a carefree summer!</h3>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.22.32021-07-05T00:00:00+00:00https://selenide.org/2021/07/05/selenide-5.22.3
<p>Good evening!</p>
<p>There was a press release here that might hurt the feelings of many of our users and committers. We regret that this has happened, and we consider this publication to be our mistake, a manifestation of the unprofessionalism of certain maintainers.</p>
<p>So just upgrade to <a href="https://github.com/selenide/selenide/milestone/126?closed=1">Selenide 5.22.3</a> with the most fresh and delicious bugfixes.</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.bbc.com/news/world-europe-57720890">
<img src="/images/2021/07/selenide-5.22.3.png" width="800" />
</a>
</center>
<h3 id="have-a-carefree-summer">Have a carefree summer!</h3>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.22.02021-06-08T00:00:00+00:00https://selenide.org/2021/06/08/selenide-5.22.0
<p>Good morning!</p>
<p>For my birthday, we made an anniversary release <a href="https://github.com/selenide/selenide/milestone/124?closed=1">Selenide 5.22.0</a>.</p>
<p>Let’s unbox the gift!</p>
<p><br /></p>
<h1 id="now-you-can-close-an-alert-to-download-a-file">Now you can close an alert to download a file</h1>
<p>Selenide has method <code class="language-plaintext highlighter-rouge">$.download()</code> which works by a very simple principle:</p>
<ol>
<li>Click</li>
<li>Wait for a new file in a downloads folder</li>
</ol>
<p>The problem is that some websites show an alert or some other dialog, and you need to close it to start downloading the file. Generally, you might need to perform some action to start the download process.</p>
<p>Now you can <a href="https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/FileDownloadToFolderTest.java">close the alert</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>or perform <a href="https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/FileDownloadViaProxyTest.java">any other action</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">-></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>See <a href="https://github.com/selenide/selenide/issues/1479">issue 1479</a> and <a href="https://github.com/selenide/selenide/pull/1481">PR 1481</a>.</p>
<p><br />
<br /></p>
<h1 id="we-improved-condition-textcasesensitive">We improved condition <code class="language-plaintext highlighter-rouge">textCaseSensitive</code></h1>
<p>… to support selected options in a <code class="language-plaintext highlighter-rouge"><select></code> element - similar to <code class="language-plaintext highlighter-rouge">Condition.text</code>.</p>
<p>Thanks to <a href="https://github.com/bereg2k">Oleg Berezhnoy</a> for <a href="https://github.com/selenide/selenide/pull/1482">PR 1482</a>.</p>
<p><br />
<br /></p>
<h1 id="we-added-selectors-bytextcaseinsensitive-and-withtextcaseinsensitive">We added selectors <code class="language-plaintext highlighter-rouge">byTextCaseInsensitive</code> and <code class="language-plaintext highlighter-rouge">withTextCaseInsensitive</code></h1>
<p>… for finding elements by text ignoring case.</p>
<h3 id="before">Before</h3>
<p>Selenide has methods for finding elements by text (case sensitive) for a long time:</p>
<ul>
<li>by the whole text: <code class="language-plaintext highlighter-rouge">$(byText("Wake up we have a tsar again")</code></li>
<li>by substring: <code class="language-plaintext highlighter-rouge">$(withText("we have a tsar")</code></li>
</ul>
<p>These selectors are case sensitive (and use XPath 1.0 inside).</p>
<h3 id="after">After</h3>
<p>Now we have added similar methods, but case insensitive:</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>These selectors can find element by text ignoring the case.</p>
<h3 id="technical-nuance">Technical nuance</h3>
<p>we could not implement this feature by XPath because string functions like
<code class="language-plaintext highlighter-rouge">lower-case</code> and <code class="language-plaintext highlighter-rouge">match</code> were added in XPath 2.0, but all popular browsers support only XPath 1.0.
That’s why we had to write <a href="https://github.com/selenide/selenide/blob/master/src/main/resources/find-elements-by-text-case-insensitive.js">a tricky JS code</a> to walk through the DOM tree.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1380">issue 1380</a> and <a href="https://github.com/selenide/selenide/pull/1381">PR 1381</a>.</p>
<p><br />
<br /></p>
<h1 id="we-added-method-drivergetsessionid">We added method <code class="language-plaintext highlighter-rouge">Driver.getSessionId()</code></h1>
<p>Basically it’s needed in Selenide-Selenoid integration.</p>
<p>Thanks to <a href="https://github.com/petroOv-PDFfiller">Petro Ovcharenko</a> for <a href="https://github.com/selenide/selenide/pull/1483">PR 1483</a>.</p>
<p><br /></p>
<h1 id="we-shortened-default-webdriver-timeouts">We shortened default webdriver timeouts</h1>
<p>There are two very strange timeouts inside of Selenium webdriver. I think it’s a problem that they are abnormally large. And you cannot change them.</p>
<p>Here are these default timeouts:</p>
<ul>
<li>connect to a webdriver: <code class="language-plaintext highlighter-rouge">connectTimeout</code> = 120000 ms = 2 minutes</li>
<li>any webdriver request: <code class="language-plaintext highlighter-rouge">readTimeout</code> = 10800000 ms = 3 hours (!)</li>
</ul>
<p>If some webdriver command hangs for whatever reason, your test will wait for 3 hours.
For example, it happens when we test an Electron application and it goes to the system tray. The test tries to take a screenshot and hangs for a long time.
I really don’t understand, is there anybody who thinks it’s reasonable?</p>
<p>In Selenide 5.22.0 we added possibility to <em>change these default timeouts</em> (it uses complex reflection under the hood).<br />
And we made these timeouts fewer (though they are still too conservative in my mind):</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">connectTimeout</code> = 1 minute</li>
<li><code class="language-plaintext highlighter-rouge">readTimeout</code> = 2 minutes</li>
</ul>
<p>Let’s consider it as a workaround and hope Selenium 4 brings a proper solution.</p>
<p>See <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>We released an update <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> which fixes <code class="language-plaintext highlighter-rouge">ClassCastException</code> in some cases.</p>
<p>Thanks to <a href="https://github.com/petroOv-PDFfiller">Petro Ovcharenko</a> for <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>We released an update <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> which upgrades to Selenide 5.22.0</p>
<p><br /></p>
<h1 id="news">News</h1>
<p>Wow! Several famous guys posted their videos about Selenide.</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 Yuriy Artamonov: <a href="https://www.youtube.com/watch?v=P-vureOnDWY&t=2758s">Modern UI Test Automation with Selenium Libraries</a></li>
<li>JetBrains post <a href="https://blog.jetbrains.com/idea/2021/06/live-stream-modern-ui-test-automation-with-selenium-libraries/">about this stream</a></li>
</ul>
<p>And a couple of older materials:</p>
<ul>
<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 />
And for dessert, the younger generation teaches Selenide:</p>
<center>
<img src="/images/2021/06/selenide-taffel.png" width="800" />
</center>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.21.02021-05-15T00:00:00+00:00https://selenide.org/2021/05/15/selenide-5.21.0
<p>Good evening!</p>
<p>We have released <a href="https://github.com/selenide/selenide/milestone/123?closed=1">Selenide 5.21.0</a>.</p>
<p>What’s new there?</p>
<p><br /></p>
<h1 id="we-removed-duplicate-screenshots-for-chained-locators">We removed duplicate screenshots for chained locators</h1>
<p>Most of Selenide methods are <em>chainable</em> (aka <em>fluent</em>), so that you can call multiple methods in a line.
Thus way you can write concise tests.</p>
<p>Something like</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">"Foo"</span><span class="o">))</span>
<span class="o">.</span><span class="na">click</span><span class="o">();</span>
</code></pre></div></div>
<p>But there has been a problem with chained calls. If such a check failed, Selenide took multiple screenshots and
added multiple steps to the report (incl. Allure report). One screenshot for <code class="language-plaintext highlighter-rouge">"table#id"</code>, another for <code class="language-plaintext highlighter-rouge">"tbody"</code> etc.<br />
Though it’s essentially a single step.</p>
<p>Though it was not critical, we have fixed this unpleasantness. Now Selenide will take one screenshot, and Allure report
will contain one line.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1055">issue 1055</a> and <a href="https://github.com/selenide/selenide/pull/1465">PR 1465</a>.</p>
<p>NB! We had to do quite a major refactoring, so something might go wrong. Feel free to share your feedback, let’s fix it quickly!</p>
<p><br /></p>
<h1 id="we-added-browserperteststrategyextension">We added BrowserPerTestStrategyExtension</h1>
<p>… for reopening a browser on every test.</p>
<p>By default Selenide reuses browser between tests (in a single thread). It’s a good idea for performance: opening a new browser takes time.<br />
We assume you take care of the AUT state: clear cache, reset data, reload a page etc. in the beginning of every test. The exact clearing logic depends on your application anyway.</p>
<p>But if you really want to open a new browser in every test, Selenide provides built-in mechanism for JUnit 4, JUnit 5 and TestNG.</p>
<p>But we recently realized one missing feature for JUnit5. Selenide had only an extension for re-opening a browser before every <em>test class</em> (<code class="language-plaintext highlighter-rouge">@ExtendWith({BrowserStrategyExtension.class}</code>), but not <em>test method</em>.</p>
<p>Now we added such an extension. If you add <code class="language-plaintext highlighter-rouge">@ExtendWith({BrowserPerTestStrategyExtension.class}</code>, Selenide will open a new browser before every <em>test method</em>.</p>
<p><em>Don’t forget it makes your tests slower!</em></p>
<p>See <a href="https://github.com/selenide/selenide/issues/1448">issue 1448</a>
Thanks to <a href="https://github.com/simple-elf">Anton Aftakhov</a> for <a href="https://github.com/selenide/selenide/pull/1450">PR 1450</a>.</p>
<p><br /></p>
<h1 id="we-added-method-hover-with-offset">We added method <code class="language-plaintext highlighter-rouge">$.hover()</code> with offset</h1>
<p>Selenide has method <code class="language-plaintext highlighter-rouge">$("div#123").hover()</code> for emulating moving cursor onto given element.
But this method puts cursor in the center point of the element, and you could not influence that.</p>
<p>Now we have overloaded method <code class="language-plaintext highlighter-rouge">$.hover()</code> with offset parameter. It allows you to specify how many pixels for the center point
should be the cursor located:</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. It seems the offset does not always work precisely. In my tests, it was located <em>near</em> this position plus-minus 30 pixels.
Feel free to share your experience with hover!</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1447">issue 1447</a> and <a href="https://github.com/selenide/selenide/pull/1461">PR 1461</a>.</p>
<p><br /></p>
<h1 id="upgraded-to-webdrivermanager-443">Upgraded to WebDriverManager 4.4.3</h1>
<p>Thanks to <a href="https://github.com/anilreddy">Anil Kumar Reddy Gaddam</a>
for <a href="https://github.com/selenide/selenide/pull/1464">PR 1464</a>
and <a href="https://github.com/selenide/selenide/pull/1469">PR 1469</a>.</p>
<p><br /></p>
<h1 id="updated-javadoc-of-many-selenide-methods">Updated javadoc of many Selenide methods</h1>
<p>… regarding lazy loading and “not recommended” phrase.</p>
<p>Now javadoc has links to these wiki articles:</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>You will probably want to discuss these topics. Great, let’s discuss them!</p>
<p>See <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>We released update <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> with support for BasicAuth when downloading files from Selenoid containers. <br />
See <a href="https://github.com/selenide/selenide-selenoid/issues/8">issue 8</a> and <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>We released update <a href="https://github.com/selenide/selenide-appium/blob/master/CHANGELOG"><code class="language-plaintext highlighter-rouge">selenide-appium:1.6.5</code></a>
with improved error message in iOS tests.<br />
See <a href="https://github.com/selenide/selenide-appium/issues/54">issue 54</a>.</p>
<p><br /></p>
<h1 id="links">Links</h1>
<p>Here are some links about Selenide we recently found:</p>
<ul>
<li>Post <a href="https://rieckpil.de/write-concise-web-tests-with-selenide-for-java-projects/">Write Concise Web Tests With Selenide for Java Projects</a> by <a href="https://github.com/rieckpil">Philip Riecks</a>.</li>
<li>Video <a href="https://www.youtube.com/watch?v=T9xns1iMbPI">Introduction to Selenide</a> from him</li>
<li>Small video tutorial <a href="https://www.youtube.com/watch?v=XPUPirH1yMs">Create Screenshots With Selenide</a> from him</li>
<li>Sample <a href="https://github.com/senpay/layered-test-framework-example-serenity-jbehave">Selenide+Serenity+JBehave</a></li>
<li>Sample <a href="https://github.com/sergiomartins8/test-automation-bootstrap/tree/master/ui-tests">Selenide+TestNG+ExtentReports</a></li>
</ul>
<p><br /></p>
<h2 id="statistics">Statistics</h2>
<p>It’s a Selenide download statistics for April, 2021:</p>
<center>
<img src="/images/2021/05/selenide.downloads.png" width="800" />
</center>
<p>We almost achieved 200 K downloads per months!</p>
<p><br /></p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.20.12021-03-23T00:00:00+00:00https://selenide.org/2021/03/23/selenide-5.20.1
<p>Good night!</p>
<p>Joe Biden was asked if he thinks <code class="language-plaintext highlighter-rouge">$$.as</code> is a killer feature. «Mmm hmm, I do», — Biden answered.</p>
<p>This is a double release notes for <a href="https://github.com/selenide/selenide/milestone/118?closed=1">Selenide 5.20.0</a> and
<a href="https://github.com/selenide/selenide/milestone/119?closed=1">Selenide 5.20.1</a>.</p>
<p><br /></p>
<h1 id="we-added-operations-with-clipboard">We added operations with clipboard</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>Note that clipboard doesn’t work on Linux without graphical environment.</p>
<p>Thanks to <a href="https://github.com/dbudim">Dmitriy Budim</a> for <a href="https://github.com/selenide/selenide/pull/1409">PR 1409</a>.</p>
<p>NB!These methods are overridden in <a href="https://github.com/selenide/selenide-selenoid">selenide-selenoid</a> plugin to work correctly in Selenoid.
We also released version <a href="https://github.com/selenide/selenide-selenoid/releases/tag/v1.1.0">1.1.0</a> of the plugin.</p>
<p><br /></p>
<h1 id="we-added-headless-mode-for-microsoft-edge">We added <code class="language-plaintext highlighter-rouge">headless</code> mode for Microsoft Edge</h1>
<p>The setting <code class="language-plaintext highlighter-rouge">Configuration.headless</code> worked only for Chrome and Firefox, now it also works for Edge.</p>
<p>(Browsers IE, Opera and Safari afaik still don’t support headless mode)</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1422">issue 1422</a>
and <a href="https://github.com/selenide/selenide/pull/1424">PR 1424</a>.</p>
<p><br /></p>
<h1 id="we-added-method-as-for-giving-collection-an-alias">We added method $$.as() for giving collection an alias</h1>
<p>As you probably remember, we added method <code class="language-plaintext highlighter-rouge">$.as()</code> in Selenide 5.17.0. It allows to give an alias (human-readable name) to any <code class="language-plaintext highlighter-rouge">SelenideElement</code>.</p>
<p>Now you can also given readable names to collections:</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>See <a href="https://github.com/selenide/selenide/issues/1389">issue 1389</a>
and <a href="https://github.com/selenide/selenide/pull/1431">PR 1431</a>.</p>
<p>NB! Don’t rush with using this feature. I personally take it as a “last sort hack”.<br />
It’s always better to see the real locator instead of a name which always may happen to be:</p>
<ul>
<li>Deceiving</li>
<li>Deprecated</li>
<li>Misleading</li>
</ul>
<p>It’s always better to invest your time in readable locator, method names, well-organized tests etc.
This is where the real power lies.</p>
<p><br /></p>
<h1 id="we-added-collection-condition-containexacttextscasesensitive">We added collection condition <code class="language-plaintext highlighter-rouge">containExactTextsCaseSensitive</code></h1>
<p>Existing method <code class="language-plaintext highlighter-rouge">$$.shouldHave(texts("a", "b", "c"))</code> checks that the collection contains exactly these elements, and not any others.
But sometimes we want a less strict check. For example, you need to check that the traded currencies list contains EUR and USD - and any others.</p>
<p>Now we have a method for such check:</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">"EUR"</span><span class="o">,</span> <span class="s">"USD"</span><span class="o">));</span>
</code></pre></div></div>
<p>Thanks to <a href="https://github.com/bereg2k">Oleg Berezhnoy</a> for <a href="https://github.com/selenide/selenide/pull/1426">PR 1426</a>.</p>
<p><strong>UPD</strong> In release Selenide 5.20.1 it was renamed to</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>Thanks to <a href="https://github.com/bereg2k">Oleg Berezhnoy</a> for <a href="https://github.com/selenide/selenide/pull/1438">PR 1438</a> and <a href="https://github.com/selenide/selenide/pull/1439">PR 1439</a>.</p>
<p><br /></p>
<h1 id="fixed-the-lost-firefoxoptions">Fixed the lost FirefoxOptions</h1>
<p>In some situations some of Firefox options could be lost. Now they are not lost anymore.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1436">issue 1436</a>.
Thanks to <a href="https://github.com/dbudim">Dmitriy Budim</a> for <a href="https://github.com/selenide/selenide/pull/1437">PR 1437</a>.</p>
<p><br /></p>
<h1 id="removed-duplicate-logging-of-navigation-methods">Removed duplicate logging of “navigation” methods</h1>
<p><code class="language-plaintext highlighter-rouge">SelenideElement</code> has several methods to find other elements:</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>Such methods were logged twice: first when you call them, and second when you call another method of the the found element.
Now we removed this duplication.</p>
<p>Thanks to <a href="https://github.com/fokinp">Pavel Fokin</a> for <a href="https://github.com/selenide/selenide/pull/1428">PR 1428</a>.</p>
<p><br /></p>
<p><br /></p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.19.02021-02-24T00:00:00+00:00https://selenide.org/2021/02/24/selenide-5.19.0
<p>Good morning!</p>
<p>You probably didn’t know, but today, February 24, is the main holiday in Estonia -
<a href="https://en.wikipedia.org/wiki/Estonian_Declaration_of_Independence">Independence Day</a>.
Exactly 103 years ago, Estonia was proclaimed an independent democratic republic.</p>
<p>And 93 years later in Estonia, in the casemates of <a href="https://codeborne.com/">Codeborne</a> company,
Selenide library was born. Isn’t that a miracle?</p>
<p>So we dedicate our new release <a href="https://github.com/selenide/selenide/milestone/116?closed=1">Selenide 5.19.0</a> to Independence Day.</p>
<p><br /></p>
<h1 id="we-fixed-draganddrop-finally">We fixed drag’and’drop, finally!</h1>
<p>Selenide has had method <code class="language-plaintext highlighter-rouge">$.dragAndDropTo()</code> for years, but de-factor it doesn’t work. Under the hood it uses
Selenium mechanism <code class="language-plaintext highlighter-rouge">Actions</code>, and something was broken in it. It just doesn’t drag the element.</p>
<p>Now we added an alternative implementation using tricky JavaScript snippet. And it seems to work in all browsers.
We even made it the default implementation.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="c1">// The working solution:</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">// Non-working solution using Actions (in case if you still want to give it a chance):</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>See <a href="https://github.com/selenide/selenide/issues/1110">issue 1110</a>.</p>
<p>Thanks to <a href="https://github.com/dbudim">Dmitriy Budim</a> for <a href="https://github.com/selenide/selenide/pull/1412">PR 1412</a>.</p>
<p><br /></p>
<h1 id="appium-support">Appium support</h1>
<p>We also released a <code class="language-plaintext highlighter-rouge">selenide-appium:1.6.2</code> update which has method <code class="language-plaintext highlighter-rouge">$.dragAndDropTo()</code> overridden,
so that it works on mobile devices too. See <a href="https://github.com/selenide/selenide-appium/pull/53/files">PR #53</a>.</p>
<p><br /></p>
<h1 id="we-fixed-method-clickusingjavascript-in-internet-explorer">We fixed method <code class="language-plaintext highlighter-rouge">$.click(usingJavascript())</code> in Internet Explorer</h1>
<p>See <a href="https://github.com/selenide/selenide/issues/1406">issue 1406</a> and
<a href="https://github.com/selenide/selenide/pull/1419">PR 1419</a>.</p>
<p><br /></p>
<h1 id="we-improved-description-of-snapshot-collections">We improved description of <code class="language-plaintext highlighter-rouge">$$.snapshot()</code> collections</h1>
<p>There is one tricky method in Selenide collections: <code class="language-plaintext highlighter-rouge">$$.snapshot()</code>.<br />
It takes a “snapshot” of the collection (fetches its elements only once), and doesn’t reload them from browser anymore.
It may be useful to speed up your tests in case of big collections. But only if you are sure that the collection
elements will not change anymore.</p>
<p>There was one tiny problem: such a snapshot didn’t look nice in reports. For example, this line:</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>when failed, looked in the report like this:</p>
<blockquote>
<p>List size mismatch: expected: = 3, actual: 2, collection: $$(2 elements)</p>
</blockquote>
<p>The description doesn’t contain selector of the original collection, only <code class="language-plaintext highlighter-rouge">(2 elements)</code>.</p>
<p>Now it also contains the selector:</p>
<blockquote>
<p>List size mismatch: expected: = 3, actual: 2, collection: #root li.snapshot(2 elements)</p>
</blockquote>
<p>Thanks to <a href="https://github.com/fokinp">Pavel Fokin</a> for <a href="https://github.com/selenide/selenide/pull/1402">PR 1402</a>.</p>
<p><br /></p>
<h1 id="added-method-getalias">Added method <code class="language-plaintext highlighter-rouge">$.getAlias()</code></h1>
<p>It returns the same value that you set with method <code class="language-plaintext highlighter-rouge">$.as("login button")</code>.<br />
Normally you don’t need this method. But it may ne useful for those who generate their own reports.
Who knows, probably some of you is developing an Allure killer…</p>
<p>Thanks to <a href="https://github.com/pavelpp">pavelpp</a> for <a href="https://github.com/selenide/selenide/pull/1415">PR 1415</a>.</p>
<p><br /></p>
<h1 id="added-refresh-and-other-events-to-selenide-log">Added “refresh” and other events to Selenide log</h1>
<p>There is a bunch of method in Selenide that are not related to web elements (like <code class="language-plaintext highlighter-rouge">refresh()</code>, <code class="language-plaintext highlighter-rouge">back()</code> etc.)
And we recently found that some of these methods were not shown in Selenide/Allure reports.
Not fatal, of course, but still, someone needs these reports for some reason…</p>
<p>Now we fixed it, and the following actions will be added to reports:</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>See <a href="https://github.com/selenide/selenide/issues/1383">issue 1383</a> and
<a href="https://github.com/selenide/selenide/pull/1404">PR 1404</a>.</p>
<p><br /></p>
<h1 id="added-nullable-annotations-to-webdriverrunner-methods">Added <code class="language-plaintext highlighter-rouge">@Nullable</code> annotations to <code class="language-plaintext highlighter-rouge">WebDriverRunner</code> methods</h1>
<p>Probably the most import is <code class="language-plaintext highlighter-rouge">@Nullable</code> annotation for method <code class="language-plaintext highlighter-rouge">WebDriverRunner.getSelenideProxy()</code>: it was not
obvious that this method can return <code class="language-plaintext highlighter-rouge">null</code> if the proxy is not started.</p>
<p>Now such an error will be highlighted in your IDE.</p>
<p>See <a href="https://github.com/selenide/selenide/commit/9b4723d090442c">commit</a>.</p>
<p><br /></p>
<h1 id="fixed-selenide-own-tests-on-non-en-machines">Fixed Selenide own tests on non-EN machines</h1>
<p>Selenide user <a href="(https://github.com/vrossellotravelc)">@vrossellotravelc</a> tried to build selenide project on a
machine which has a default language other than English (was it French or Spanish?)</p>
<p>We found that a couple of Selenide own tests contained hard-coded formatting of <code class="language-plaintext highlighter-rouge">Duration</code>, which can differ
in other locales.</p>
<p>Now those tests are fixed so that it cannot happen anymore. How? Welcome to the PR!</p>
<p>Thanks to <a href="https://github.com/vrossellotravelc">Vicente Rossello Jaume</a> for <a href="https://github.com/selenide/selenide/pull/1408">PR 1408</a>.</p>
<p><br /></p>
<h1 id="statistics">Statistics</h1>
<p>The latest Selenide downloads statistics:</p>
<center>
<img src="/images/2021/02/selenide.downloads.png" width="800" />
</center>
<p><br /></p>
<h1 id="traditions">Traditions</h1>
<p>That’s it for today.</p>
<p>While you are updating, I’m going to find a glass of vodka and a sprat sandwich.<br />
It’s a tradition in Estonia for independence day, you know.</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.18.12021-02-11T00:00:00+00:00https://selenide.org/2021/02/11/selenide-5.18.1
<p>Hi all!</p>
<p>We have release a small update <a href="https://github.com/selenide/selenide/milestone/115?closed=1">Selenide 5.18.1</a>.</p>
<p>Let’s look at the changes:</p>
<p><br /></p>
<h1 id="added-method-selenidegetsessionstorage">Added method <code class="language-plaintext highlighter-rouge">Selenide.getSessionStorage()</code></h1>
<p>… similar to <code class="language-plaintext highlighter-rouge">Selenide.getLocalStorage()</code> added in 5.15.0.</p>
<p>They both have the same set of methods: <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> etc.</p>
<blockquote>
<p>Sometimes it’s useful to set some flag to <code class="language-plaintext highlighter-rouge">sessionStorage</code> to <code class="language-plaintext highlighter-rouge">localStorage</code> to emulate some user action or
toggle some features or settings.</p>
</blockquote>
<p>Thanks to <a href="https://github.com/dbudim">Dmitriy Budim</a> for <a href="https://github.com/selenide/selenide/pull/1400">PR 1400</a>.</p>
<p>P.S. FYI <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage">difference between localStorage and sessionStorage</a>.</p>
<p><br /></p>
<h1 id="fixed-error-message-for-filterbyand">Fixed error message for <code class="language-plaintext highlighter-rouge">$$.filterBy(and(..))</code></h1>
<p>As you know, Selenide provides powerful API for filtering and validating collections.</p>
<p>User <a href="https://github.com/fokinp">Pavel Fokin</a> found that the error message can look misleading when
the collection is filtered with <code class="language-plaintext highlighter-rouge">and</code> condition (a combination of other conditions):</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>The output was a bit misleading (because it showed only the last checked condition):</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>Now the output contains all conditions:</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>See <a href="https://github.com/selenide/selenide/issues/1392">issue 1392</a>.<br />
Thanks to <a href="https://github.com/fokinp">Pavel Fokin</a> for <a href="https://github.com/selenide/selenide/pull/1393">PR 1393</a>.</p>
<p><br /></p>
<h1 id="pass-noproxy-option-from-user-provided-proxy-to-selenide-proxy">Pass “noproxy” option from user-provided proxy to Selenide proxy</h1>
<p>As you know, Selenide can run its own embedded proxy server (used to download files, intercept requests etc.)
It’s also possible to provide Selenide your own proxy. Then Selenide uses both proxies, one through the other.</p>
<p>Every proxy can have a setting “noproxy” which often has value “localhost”. It mean that all requests
<em>except “http://localhost:*“</em> should be proxied. And this setting was lost when running Selenide
with two proxies, Thus Selenide could not run requests to localhost.</p>
<p>Now Selenide passes “noproxy” setting from your proxy to its own proxy.</p>
<p><em>Localhost is a delicate thing!</em></p>
<p>Thanks to <a href="https://github.com/BorisOsipov">Boris Osipov</a> for <a href="https://github.com/selenide/selenide/pull/1390">PR 1390</a>.</p>
<p><br /></p>
<h1 id="upgraded-to-netty-4159final-and-littleproxy-202">Upgraded to Netty 4.1.59.Final and LittleProxy 2.0.2</h1>
<p>It is unlikely that you will read them, but here are the release notes for
<a href="https://netty.io/news/2021/02/08/4-1-59-Final.html">Netty 4.1.59.Final</a> and
<a href="https://github.com/mrog/LittleProxy/blob/master/RELEASE_NOTES.md">LittleProxy 2.0.2</a>.
At lease they fixed some security issue and a memory leak.</p>
<p><br /></p>
<p>It’s all for today. Feel free to update and share your feedback. <br />
Create issues <a href="https://github.com/selenide/selenide/issues/new">in github</a>, complain <a href="https://gitter.im/codeborne/selenide">in chats</a>,
swear <a href="https://twitter.com/selenide">in twitter</a>.</p>
<p><br />
<em>Github is stronger than bugs!</em></p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.18.02021-01-23T00:00:00+00:00https://selenide.org/2021/01/23/selenide-5.18.0
<p>Good evening!</p>
<p>Today is January, 23.</p>
<p>Let’s meet the new update: <a href="https://github.com/selenide/selenide/milestone/113?closed=1">Selenide 5.18.0</a>.</p>
<p>Let me invite you to take a small virtual tour of the changes in 5.18.0. <br />
Make yourself comfortable.</p>
<p><br /></p>
<h1 id="we-disabled-webdriver-logs-by-default">We disabled webdriver logs by default</h1>
<p>Starting from version 5.13.0, Selenide wrote webdriver logs to files <code class="language-plaintext highlighter-rouge">build/reports/tests/webdriver.uuid.log</code>.<br />
It seemed to be useful at that moment. But later we realized that these logs take quite a lot of disk space,
and nobody really needs to read them in most cases. That’s why we decided to disable them by default.</p>
<p>If you need those webdriver logs, you can still enable them with setting
<code class="language-plaintext highlighter-rouge">Configuration.webdriverLogsEnabled = true</code>.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1365">issue 1365</a> and <a href="https://github.com/selenide/selenide/pull/1379">PR 1379</a>.</p>
<p><br /></p>
<h1 id="changed-timeout-parameter-type-from-long-to-duration">Changed “timeout” parameter type from Long to Duration</h1>
<p>… in collection methods. Now instead of</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>it is fashionable to write</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>See <a href="https://github.com/selenide/selenide/issues/1377">issue 1377</a>.<br />
Thanks to <a href="https://github.com/ostap-oleksyn">Ostap Oleksyn</a> for <a href="https://github.com/selenide/selenide/pull/1377">PR 1377</a>.</p>
<p><br /></p>
<h1 id="speed-up-search-of-inner-shadow-dom-elements">Speed up search of inner shadow dom elements</h1>
<p>One of features that do exist in Selenide, but not in Selenium webdriver is <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>There might be multiple shadow roots inside of other shadow roots.<br />
To find all elements inside inner shadow roots, method <code class="language-plaintext highlighter-rouge">$(shadowCss())</code> performed a JavaScript snippet in loop for
every shadow root separately. It might be slow because every call to webdriver takes time.</p>
<p>Now <code class="language-plaintext highlighter-rouge">$(shadowCss())</code> calls one <a href="https://github.com/selenide/selenide/blob/master/src/main/resources/find-in-shadow-roots.js">even more trickier recursive JavaScript</a>
which finds all elements in all inner shadow roots with one call.</p>
<p>See <a href="https://github.com/selenide/selenide/pull/1373">PR 1373</a>.</p>
<p>A separate “thank you” goes to <a href="https://github.com/sakamoto66">sakamoto66</a> for
<a href="https://github.com/selenide/selenide/issues/1246">issue 1246</a> and
<a href="https://github.com/selenide/selenide/pull/1233">PR 1233</a>
which unfortunately was not merged, but inspired us for this optimization.</p>
<p><br /></p>
<h1 id="fixed-checks-shouldnotand-and-shouldnotor">Fixed checks <code class="language-plaintext highlighter-rouge">$.shouldNot(and(...))</code> and <code class="language-plaintext highlighter-rouge">$.shouldNot(or(...))</code></h1>
<p>Selenide user <a href="https://github.com/pavelpp">pavelpp</a> detected a bug in Selenide when used <code class="language-plaintext highlighter-rouge">not</code> in combination with <code class="language-plaintext highlighter-rouge">and</code> and <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">// works</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">// fails</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">// fails</span>
</code></pre></div></div>
<p>Now we fixed it. All three lines don’t throw errors anymore.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1369">issue 1369</a> and <a href="https://github.com/selenide/selenide/pull/1370">PR 1370</a>.</p>
<p>By the way, we now forbid using <code class="language-plaintext highlighter-rouge">and</code> and <code class="language-plaintext highlighter-rouge">or</code> with only one condition.
In other words, line <code class="language-plaintext highlighter-rouge">or("foo", visible)</code> doesn’t compile anymore.
You have to use at least two condition, like <code class="language-plaintext highlighter-rouge">or("foo", visible, enabled)</code>.</p>
<p>Agree, this is logical.</p>
<p><br /></p>
<h1 id="we-detect-conflict-in-browsername-capability">We detect conflict in “browserName” capability</h1>
<p>We recently realized that there are two settings for specifying browser:</p>
<ol>
<li>The primary - <code class="language-plaintext highlighter-rouge">Configuration.browser</code></li>
<li>Another - <code class="language-plaintext highlighter-rouge">Configuration.browserCapabilities["browserName"]</code> (I don’t really know why it’s needed)</li>
</ol>
<p>And you might get an unexpected browser opened if you haven’t set the first one, but set the second one.
Now Selenide detects such a conflict and throws an exception:</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>Let me repeat: setting <code class="language-plaintext highlighter-rouge">Configuration.browser</code> is enough in all cases. As far as I know, the second setting is never needed.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1366">issue 1366</a> and <a href="https://github.com/selenide/selenide/pull/1374">PR 1374</a>.</p>
<p><br /></p>
<h1 id="fixed-displaying-timeout-parameter-in-reports">Fixed displaying timeout parameter in reports</h1>
<p>Recently we added to <code class="language-plaintext highlighter-rouge">$.should*</code> methods parameter <code class="language-plaintext highlighter-rouge">timeout</code> of type <code class="language-plaintext highlighter-rouge">Duration</code>.<br />
Then we realized it was displayed quite unclearly in Selenide/Allure reports.</p>
<p>For example, line <code class="language-plaintext highlighter-rouge">$("h1").shouldBe(visible, Duration.ofSeconds(1))</code> looked like this in a report:</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>Though this “PT1M” is an ISO-compatible representation and means “time period 1 minute”, we decided to replace it by
more familiar “300 ms”, “1s”, “1.500 s.” etc.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1376">issue 1376</a> and <a href="https://github.com/selenide/selenide/pull/1378">PR 1378</a>.</p>
<p><br /></p>
<h1 id="upgraded-to-webdrivermanager-431">Upgraded to WebDriverManager 4.3.1</h1>
<p>As usually, see their changelog <a href="https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md">here</a>.</p>
<p><br /></p>
<p>It’s the end of our excursion. Feel free to update and share your feedback. <br />
Create issues <a href="https://github.com/selenide/selenide/issues/new">in github</a>, complain <a href="https://gitter.im/codeborne/selenide">in chats</a>,
swear <a href="https://twitter.com/selenide">in twitter</a>.</p>
<h2 id="news">News</h2>
<p>Here is an final downloads statistics of Selenide for year 2020. Not bad!</p>
<center>
<img src="/images/2021/01/selenide.downloads.png" width="800" />
</center>
<p><br />
Happy current year!
<br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.17.22020-12-30T00:00:00+00:00https://selenide.org/2020/12/30/selenide-5.17.2
<p>Good morning!</p>
<p>The gnomes still cannot calm down. Tomorrow morning they will bring you the last present in your socks:
release <a href="https://github.com/selenide/selenide/milestone/110?closed=1">Selenide 5.17.2</a>.</p>
<p><br /></p>
<h1 id="make-commands-return-selenideelement-instead-webelement">Make <code class="language-plaintext highlighter-rouge">Commands</code> return <code class="language-plaintext highlighter-rouge">SelenideElement</code> instead <code class="language-plaintext highlighter-rouge">WebElement</code></h1>
<p>It allows you chaining <code class="language-plaintext highlighter-rouge">$.execute(Command)</code> with other Selenide methods, thus making your tests even more concise
and expressive:</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>Thanks to <a href="https://github.com/BorisOsipov">Boris Osipov</a> for <a href="https://github.com/selenide/selenide/pull/1355">PR 1355</a>.</p>
<p><br /></p>
<h1 id="fixed-method-setvaluenull">Fixed method <code class="language-plaintext highlighter-rouge">$.setValue(null)</code></h1>
<p>See <a href="https://github.com/selenide/selenide/issues/1356">issue 1356</a>.
Thanks to <a href="https://github.com/dzem">Dmitriy Zemlyanitsyn</a> for <a href="https://github.com/selenide/selenide/pull/1357">PR 1357</a>.</p>
<p><br /></p>
<h1 id="enabled-soft-asserts-in-beforeall-and-afterall-methods-in-junit-5">Enabled soft asserts in @BeforeAll and @AfterAll methods (in JUnit 5)</h1>
<p>See <a href="https://github.com/selenide/selenide/issues/981">issue 981</a>,
<a href="https://github.com/selenide/selenide/issues/1070">issue 1070</a> and
<a href="https://github.com/selenide/selenide/pull/1359">PR 1359</a>.</p>
<p><br /></p>
<h1 id="fixed-file-selenide-5172-javadocjar">Fixed file <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>now it contains javadoc for all classes.</p>
<p><br /></p>
<p><br />
Once again, Happy New Year!
<br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released 5.17.02020-12-26T00:00:00+00:00https://selenide.org/2020/12/26/selenide-5.17.0
<p>Good night!</p>
<p>I am passionate about Catholic Christmas.
Because it was on Christmas that the terrorists took over the Nakatomi plaza and Bruce killed Hans Gruber.
And then he blew up the plane with a lighter.</p>
<p>So catch the Christmas release <a href="https://github.com/selenide/selenide/milestone/108?closed=1">Selenide 5.17.0</a>.</p>
<p><br /></p>
<h1 id="added-method-asname">Added method $.as(“name”)</h1>
<p>We added method <code class="language-plaintext highlighter-rouge">as</code>, so that you can give elements readable names.</p>
<p>To feel the difference, let’s compare the following two lines in test:</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>The test result looks like this:</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>In the last line, we see a readable name “Login button” instead of long unreadable xpath.</p>
<p>NB! Don’t rush with using this feature. I personally take it as a “last sort hack”.<br />
It’s always better to see the real locator instead of a name which always may happen to be:</p>
<ul>
<li>Deceiving</li>
<li>Deprecated</li>
<li>Misleading</li>
</ul>
<p>It’s always better to invest your time in readable locator, method names, well-organized tests etc.
This is where the real power lies.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1200">issue 1200</a> and <a href="https://github.com/selenide/selenide/pull/1353">PR 1353</a>.</p>
<p><br /></p>
<h1 id="added-bunch-of-default-options-to-headless-chrome">Added bunch of default options to headless chrome</h1>
<p>We added the same default options to headless chrome <a href="https://github.com/puppeteer/puppeteer/blob/7a2a41f2087b07e8ef1feaf3881bdcc3fd4922ca/src/Launcher.js#L261">as in Puppeteer</a>.<br />
We assume that Puppeteer guys are smart, so we do like them. :)</p>
<p>Thanks to <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/1329">PR 1329</a>.</p>
<p><br /></p>
<h1 id="fixed-byshadowcssfindelements">Fixed <code class="language-plaintext highlighter-rouge">ByShadowCss.findElements</code></h1>
<p>It returned only subset of elements in a particular case: when DOM contained multiple <em>inner shadow hosts</em>.</p>
<p>Now it returns all the elements.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1346">issue 1346</a>.
Thanks to <a href="https://github.com/dpeger">Daniel H. Peger</a> for <a href="https://github.com/selenide/selenide/pull/1347">PR 1347</a>.</p>
<p><br /></p>
<h1 id="added-should-methods-with-custom-timeout">Added $.should* methods with custom timeout</h1>
<p>As you know, there are two major groups of methods in Selenide:</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> – use default timeout</li>
<li><code class="language-plaintext highlighter-rouge">$.waitUntil</code> / <code class="language-plaintext highlighter-rouge">$.waitWhile</code> – use given timeout</li>
</ol>
<p><code class="language-plaintext highlighter-rouge">$.wait*</code> are useful for “long” actions that last longer than the default timeout (which is 4 seconds by default).</p>
<p><br /></p>
<p>The problem with <code class="language-plaintext highlighter-rouge">$.wait*</code> methods is purely grammatical: Selenide built-in conditions don’t sound correctly with verb “wait”:</p>
<ol>
<li><code class="language-plaintext highlighter-rouge">element should have text</code> - sounds right</li>
<li><code class="language-plaintext highlighter-rouge">element wait until text</code> - doesn’t sound right</li>
</ol>
<p>Now you can replace <code class="language-plaintext highlighter-rouge">$.waitUntil(hasText("bob"), 18_000)</code> by <code class="language-plaintext highlighter-rouge">$.shouldHave(text("bob"), Duration.ofSeconds(18))</code>.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1136">issue 1136</a>,
<a href="https://github.com/selenide/selenide/issues/1338">issue 1338</a> and
<a href="https://github.com/selenide/selenide/pull/1340">PR 1340</a>.</p>
<p><br /></p>
<h1 id="page-objects">Page objects</h1>
<p>The next block of improvements concerns the Page Objects.</p>
<p>As you know, in Selenide it’s possible to create page objects</p>
<ul>
<li>with fields annotated with <code class="language-plaintext highlighter-rouge">@FindBy</code>,</li>
<li>which can be standard selenium <code class="language-plaintext highlighter-rouge">WebElement</code>,</li>
<li>or our <code class="language-plaintext highlighter-rouge">SelenideElement</code>,</li>
<li>or even reusable components <code class="language-plaintext highlighter-rouge">ElementsContainer</code> which can be used to compose more complex page objects.</li>
</ul>
<p>And it all works in the best traditions of selenide: lazy loading and reloading of elements etc.</p>
<p><br /></p>
<p>There were some issues with those <code class="language-plaintext highlighter-rouge">@FindBy</code> fields:</p>
<ol>
<li>lazy loading didn’t work for PO fields of type <code class="language-plaintext highlighter-rouge">List<ElementsContainer></code> (see issue <a href="https://github.com/selenide/selenide/issues/282">282</a> and <a href="https://github.com/selenide/selenide/issues/482">482</a>)</li>
<li>PO fields of generic types were not supported (see <a href="https://github.com/selenide/selenide/issues/694">issue 694</a>)</li>
</ol>
<p>It was hard to fix. I had to dive into (quite old) code and refactor it.
I had to strain my brains and apply all my remnants of the former abstract thinking. :)</p>
<p>That’s why these two pull requests are my pride:</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<ElementsContainer></code></a></li>
</ul>
<p><br /></p>
<h1 id="and-finally-a-couple-of-technical-improvements">And finally, a couple of technical improvements:</h1>
<ul>
<li>split Selenide project to subprojects - see <a href="https://github.com/selenide/selenide/pull/1348">PR 1348</a></li>
<li>fixed Selenide tests that depended on OS - see <a href="https://github.com/selenide/selenide/issues/1344">issue 1344</a> and
<a href="https://github.com/selenide/selenide/pull/1345">PR 1345</a>, thanks to <a href="https://github.com/dpeger">Daniel H. Peger</a></li>
<li>cleaned up <code class="language-plaintext highlighter-rouge">Plugins</code> code – thanks to <a href="https://github.com/yorlov">Yuri Orlov</a> for <a href="https://github.com/selenide/selenide/pull/1343">PR 1343</a></li>
<li>upgraded to browserup-proxy:2.1.2 and guava:30.1-jre</li>
<li>added support for chrome 88, edge 89, opera 73</li>
</ul>
<p><br /></p>
<h3 id="known-issues">Known issues:</h3>
<ul>
<li>file <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>
happened to be incomplete: it doesn’t contain javadoc for some of Selenide classes. Will be fixed in 5.17.1.</li>
</ul>
<p><br /></p>
<h1 id="summarizing">Summarizing</h1>
<p>In general, we end the year on a positive note:<br />
performed a non-trivial refactoring and fixed several old pains. <br />
We are entering the New Year with only one screen in <a href="https://github.com/selenide/selenide/issues">github issues</a> instead of two.</p>
<p>And the number of downloads of selenide has grown over the year from 102 to 167 thousand.</p>
<center>
<img src="/images/2020/12/selenide.downloads.png" width="800" />
</center>
<p><br />
Happy New Year!
<br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.16.22020-11-25T00:00:00+00:00https://selenide.org/2020/11/25/selenide-5.16.2
<p>Good morning!</p>
<p>We released <a href="https://github.com/selenide/selenide/milestone/109?closed=1">Selenide 5.16.2</a>.</p>
<p>Please don’t think that recent release <a href="/2020/11/20/selenide-5.16.0/">Selenide 5.16.0</a> had a lot of bugs.<br />
Not at all.</p>
<p>This release 5.16.2 is a bunch of fixes for old small issues.</p>
<p>Briefly:</p>
<h2 id="selenide-5.16.2">Release <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">Release <a href="https://github.com/selenide/selenide/milestone/106?closed=1">5.16.1</a> (23.11.2020)</h2>
<p>Here we had two fixes to run Chrome with extensions.</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">News</h2>
<p>Once there is room left, I will share brand new links:</p>
<ul>
<li>Example from LambdaTest: <a href="https://github.com/LambdaTest/selenide-testng-sample">selenide-testng-sample</a></li>
<li>Video about Selenide on Portugal: <a href="https://www.youtube.com/watch?v=yOfrqZUsFuU&feature=youtu.be&ab_channel=BluesoftLabs">Testes de Aceitação em Java com Selenide, Adriano Magalhães</a></li>
<li>Selenide course somewhere in Brazil: <a href="https://inoveteste.com.br/automacao-web-descomplicada-com-selenide/">Automação Web Descomplicada Com Selenide</a></li>
<li>Visual testing: <a href="https://medium.com/automated-visual-testing-with-applitools/getting-started-with-the-applitools-sdk-653f2cd1ad48">Applitools+Selenide</a></li>
<li>Project sample: <a href="https://github.com/bmurmistro/applitools">Getting started with applitools</a></li>
</ul>
<p><br /></p>
<p>Stay tuned for Selenide 5.17.0!</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.16.02020-11-20T00:00:00+00:00https://selenide.org/2020/11/20/selenide-5.16.0
<p>Good night!</p>
<p>We released <a href="https://github.com/selenide/selenide/milestone/105?closed=1">Selenide 5.16.0</a>.</p>
<h2 id="plugin-system">Plugin system</h2>
<p>One of the major plans for this year in <a href="https://github.com/selenide/selenide/wiki/Selenide-Roadmap">Selenide roadmap</a>
was to create a plugins system. It took time, but now</p>
<p><strong>the day has come!</strong></p>
<p>Currently there are two Selenide plugins available:</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>We will describe them in following posts.</p>
<p>Apparently, we are going to create next plugins for Allure, JUnit, TestNG, AShot.<br />
<em>Please share your ideas too!</em></p>
<p>See <a href="https://github.com/selenide/selenide/issues/1051">issue #1051</a> and
<a href="https://github.com/selenide/selenide/pull/1264">PR #1264</a>,
<a href="https://github.com/selenide/selenide/pull/1317">PR 1317</a> and
<a href="https://github.com/selenide/selenide/pull/1321">PR 1321</a>.</p>
<h2 id="error-messages">Error messages</h2>
<p>One of core Selenide functions is forming error messages in case of test failures.<br />
Sometimes these error messages can also be incomplete or unclear, especially in some corner cases.<br />
In this release, we did a whole bunch of fixes for error messages.</p>
<h3 id="improved-error-messages-for-and-and-not-checks">Improved error messages for AND and NOT checks</h3>
<p>A canonical way to perform a negative check in Selenide is method <code class="language-plaintext highlighter-rouge">shouldNotHave</code>.<br />
And if you want to perform multiple checks - just write them in a line using commas:</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>But there are alternative methods <code class="language-plaintext highlighter-rouge">Condition.not</code> and <code class="language-plaintext highlighter-rouge">Condition.and</code> for specific cases. For example, you can declare
composite conditions, thus creating DSL for your tests.</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>We found that these methods showed incomplete information in test reports:</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>The problem is that we don’t see the expected text (“admin”) and other conditions.</p>
<p>Now we fixed this problem, and you will see the expected text:</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>Thanks to <a href="https://github.com/fokinp">Pavel Fokin</a> for <a href="https://github.com/selenide/selenide/pull/1306">PR 1306</a>
and <a href="https://github.com/selenide/selenide/pull/1300">PR 1306</a>.</p>
<p><br /></p>
<h3 id="added-information-about-parents">Added information about parents</h3>
<p>In Selenide, you can find elements inside other elements. Like this:</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>But if such a check failed, you could see only the child element’s locator in the error message:</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>Now we added information about its parents too:</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>Thanks to <a href="https://github.com/petroOv-PDFfiller">Petro Ovcharenko</a> for <a href="https://github.com/selenide/selenide/pull/1312">PR 1312</a>.</p>
<p><br />
<br /></p>
<h3 id="we-added-actual-texts-for-owntext-and-exactowntext-checks">We added actual texts for <code class="language-plaintext highlighter-rouge">ownText</code> and <code class="language-plaintext highlighter-rouge">exactOwnText</code> checks</h3>
<p>As you remember, in Selenide 5.15.0 we added checks <code class="language-plaintext highlighter-rouge">ownText</code> and <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>But if such check failed, you didn’t see the actual “own text”, but only the whole element’s text with its children:</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"><</span><span class="n">div</span> <span class="n">id</span><span class="o">=</span><span class="s">"child_div1"</span><span class="o">></span><span class="nc">Son</span><span class="o"></</span><span class="n">div</span><span class="o">></span><span class="err">'</span>
</code></pre></div></div>
<p>Now we added “Actual value” line with element’s own text:</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"><</span><span class="n">div</span> <span class="n">id</span><span class="o">=</span><span class="s">"child_div1"</span><span class="o">></span><span class="nc">Son</span><span class="o"></</span><span class="n">div</span><span class="o">></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>See <a href="https://github.com/selenide/selenide/issues/1261">issue 1261</a> and <a href="https://github.com/selenide/selenide/pull/1294">PR 1294</a>.</p>
<p><br />
<br /></p>
<h3 id="we-throw-the-right-exception-if-you-try-to-upload-a-wrong-file">We throw the right exception if you try to upload a wrong file</h3>
<p>If you tried to upload a missing file:</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>you got an incorrect exception:</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>Not a big deal, but sometimes is might be misleading.</p>
<p>Now we throw the right exception:</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>See <a href="https://github.com/selenide/selenide/issues/987">issue 987</a> and <a href="https://github.com/selenide/selenide/pull/1301">PR 1301</a>.</p>
<p><br /></p>
<blockquote>
<p>The root problem that Selenium doesn’t have dedicated exception classes for all possible corner cases.
See <a href="https://github.com/selenide/selenide/issues/1293">issues 1293</a> for example.
Also some webdriver implementations can throw non-reasonable exceptions - for example, IEDriver threw
<code class="language-plaintext highlighter-rouge">Throwable</code> instead of <code class="language-plaintext highlighter-rouge">ElementNotFound</code> when I checked it last time.</p>
<p>That’s why we decided to use a conservative strategy in Selenide: if we couldn’t detect the problem precisely, we
assume that element not found, and you will see the real problem in the “caused by” block anyway.</p>
</blockquote>
<p><br />
<br /></p>
<h3 id="show-clickoptions-in-the-report">Show ClickOptions in the report</h3>
<p>As you remember, in Selenide 5.15.0 we added generic methods for clicking with all kinds of options:</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>And again, we found that such a line was not readably in report:</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>Now we made it readable:</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>See <a href="https://github.com/selenide/selenide/issues/1302">issue 1302</a> and <a href="https://github.com/selenide/selenide/pull/1303">PR 1303</a>.</p>
<p><br /></p>
<h2 id="other-changes">Other changes</h2>
<h3 id="we-added-check-shouldhaveexacttextscasesensitiveinanyorder">We added check <code class="language-plaintext highlighter-rouge">$$.shouldHave(exactTextsCaseSensitiveInAnyOrder(...))</code></h3>
<p>There are multiple collection checks in 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="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">"john"</span><span class="o">,</span> <span class="s">"bob"</span><span class="o">,</span> <span class="s">"katie"</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">"john"</span><span class="o">,</span> <span class="s">"katie"</span><span class="o">,</span> <span class="s">"bob"</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">"john"</span><span class="o">,</span> <span class="s">"bob"</span><span class="o">,</span> <span class="s">"katie"</span><span class="o">));</span> <span class="c1">// case-insensitive, full string match</span>
</code></pre></div></div>
<p>Now we got one more:</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">"John"</span><span class="o">,</span> <span class="s">"Bob"</span><span class="o">,</span> <span class="s">"Katie"</span><span class="o">));</span>
</code></pre></div></div>
<p>Thanks to <a href="https://github.com/plagov">Vitali Plagov</a> and <a href="https://github.com/selenide/selenide/pull/1286">PR 1286</a>.</p>
<p><br /></p>
<h3 id="we-support-hrefs-with-special-symbols">We support <code class="language-plaintext highlighter-rouge">href</code>s with special symbols</h3>
<p>As you remember, in Selenide 5.15.0 we added check <code class="language-plaintext highlighter-rouge">href</code>.<br />
But it didn’t support <code class="language-plaintext highlighter-rouge">href</code> values with escaped characters, like in the second line:</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>Now it’s fixed.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1298">issue 1298</a>.<br />
Thanks to <a href="https://github.com/rerednaw">rerednaw</a> and <a href="https://github.com/selenide/selenide/pull/1299">PR 1299</a>.</p>
<p><br /></p>
<h3 id="allow-chrome-to-download-multiple-files">Allow Chrome to download multiple files</h3>
<p>There are such tricky links that cause downloading of two or more files.<br />
We found that Chrome shows a dialog “Are you sure you want all these files?” in this case. And this dialog blocks your
test until user clicks “ok”.</p>
<blockquote>
<p>The worst thing about this problem is that it is very difficult to repeat it by hand:
the browser shows the dialog only the first time, so when running locally, most likely
you will not see it, and the test will be green.</p>
</blockquote>
<p>To fix this problem, we added an option <code class="language-plaintext highlighter-rouge">profile.default_content_setting_values.automatic_downloads=1</code> when running
Chrome browser. This option allows Chrome to download multiple files without any dialogs.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1307">issue 1307</a>.<br />
Thanks to <a href="https://github.com/vinogradoff">Alexei Vinogradov</a> and <a href="https://github.com/selenide/selenide/pull/1308">PR 1308</a>.</p>
<p><br /></p>
<h3 id="we-allow-downloading-files-with-slashes-in-name">We allow downloading files with slashes in name</h3>
<p>Until now, method <code class="language-plaintext highlighter-rouge">download</code> didn’t allow a file which has slash in name:</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">--></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>It seemed logical to us, because no file system allows creating of such files. <br />
But it turned out that sometimes the slash is quite logical - for example, as a separator in dates.
And browsers can download such files. For example, Chrome simply replaces the slashes with underscores.</p>
<p>Now Selenide also does it.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1322">issue 1322</a> and <a href="https://github.com/selenide/selenide/pull/1323">PR 1323</a>.</p>
<p><br /></p>
<h3 id="fixed-guava-version-300-jre">Fixed Guava version 30.0-jre</h3>
<p>Oh, Guava!</p>
<p>In Selenide own code, Guava is not used. We don’t directly need it. <br />
But many other libraries still use <em>different versions of Guava</em>: Selenium, LittleProxy, BrowserUpProxy, Checkstyle…</p>
<p>Selenide users periodically experienced problems when Maven or Gradle fetched transitively a wrong Guava version,
and Selenide didn’t properly work. <br />
We are tired of it. Now Selenide explicitly declares a dependency on latest Guava version <code class="language-plaintext highlighter-rouge">30.0-jre</code>. We hope it will
fix all those endless dependency issues.</p>
<p><br /></p>
<h3 id="we-migrated-to-github-actions">We migrated to Github Actions</h3>
<p>As in any decent project, Selenide has its own set of automated tests (unit and integration), and they run
automatically for all branches on a CI server. We used to use Travis CI which provides a free service
for open-source projects. Thank them very much for the years of joint work. :)</p>
<p>But this year, Github started their own CI service “Github actions”. It seemed reasonable to migrate to it.</p>
<p>Now all Selenide builds can be found <a href="https://github.com/selenide/selenide/actions">right on github</a>.</p>
<p>Thanks to <a href="https://github.com/BorisOsipov">Boris Osipov</a> and <a href="https://github.com/selenide/selenide/pull/1319">PR 1319</a>.</p>
<p><br /></p>
<h2 id="the-ned">The ned</h2>
<p>It was a long text, but you mastered it. All good fellows!</p>
<p>As usually, update, try, experiment and feel free to report problems and share ideas.</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Why proxy does not work in Selenoid?2020-11-17T00:00:00+00:00https://selenide.org/2020/11/17/why-proxy-does-not-work-in-selenoid
<p>Good night!</p>
<p>Today we will finally reveal the secret of why proxy does not often work in Selenoid.</p>
<h3 id="the-goal-download-a-file">The goal: download a file</h3>
<ul>
<li>We run tests which open browsers in Selenoid containers (usually with Selenide, but it’s not important in this case).</li>
<li>We want to download a file during the test.</li>
<li>Default method <code class="language-plaintext highlighter-rouge">$.download()</code> doesn’t work (for example, because the download starts by submitting a form - there is no direct link to the file).</li>
<li>That’s why we want to <a href="https://selenide.org/2019/12/10/advent-calendar-download-files/">download file via proxy</a>.</li>
</ul>
<h3 id="our-plan">Our plan</h3>
<ol>
<li>Create a project</li>
<li>Add BrowserUpProxy dependency as shown in Selenide documentation:
<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>Copy-paste a typical boilerplate to run browsers in 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>And write a test, something like this:
<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="the-problem">The problem</h3>
<p>And we get an error when opening a browser:</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="aaa-panic-mode">AAA, panic mode!</h3>
<p>At this point, most people panic, go through a bunch of browser options and Selenide settings
and in the end write to one of the QA chats.</p>
<p>But all you had to do was read the log carefully.</p>
<p>The problem is clearly visible in the log:</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="tune-the-dependencies">Tune the dependencies</h3>
<p>Exception <code class="language-plaintext highlighter-rouge">NoSuchMethodError</code> clearly says that we have a problem with dependencies:
apparently, there are two JAR’s with incompatible versions in classpath.</p>
<p>The humanity invented a vaccine against this a long time ago.
I wonder why so many people still don’t know it.</p>
<p>Let’s run command</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">gradle dependencies</code>, or</li>
<li><code class="language-plaintext highlighter-rouge">mvn dependency:tree</code></li>
</ul>
<p>And we clearly see which JAR’s have which versions. Let’s look for something similar to “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>We have two jars with different versions: <code class="language-plaintext highlighter-rouge">netty-codec:4.1.44.Final</code> and <code class="language-plaintext highlighter-rouge">netty-all:4.1.34.Final</code>.</p>
<h3 id="treating-dependencies">Treating dependencies</h3>
<p>There are many ways to fix the problem.
Probably the easiest one is to declare Netty versions explicitly in <code class="language-plaintext highlighter-rouge">build.gradle</code> or <code class="language-plaintext highlighter-rouge">pom.xml</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>(actually it’s enough to declare just one of them. <em>Homework for you: which one and why?</em>)</p>
<p>Now command <code class="language-plaintext highlighter-rouge">gradle dependencies</code> shows that Netty versions are matching:</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 -> 4.1.54.Final
+--- xyz.rogfam:littleproxy:2.0.0-beta-5
| +--- io.netty:netty-all:4.1.34.Final -> 4.1.54.Final
</code></pre></div></div>
<p>The test runs, proxy works, file is being downloaded. Everyone is happy.</p>
<h3 id="moral">Moral</h3>
<p>Pay attention to the logs, our smaller brothers!</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.15.02020-09-26T00:00:00+00:00https://selenide.org/2020/09/26/selenide-5.15.0
<p>Hi all!</p>
<p>We released <a href="https://github.com/selenide/selenide/milestone/104?closed=1">Selenide 5.15.0</a>.</p>
<p>What’s new?</p>
<h2 id="we-added-setting-configurationpageloadtimeout--default-value-is-30-seconds">We added setting <code class="language-plaintext highlighter-rouge">Configuration.pageLoadTimeout</code> <br /> (default value is 30 seconds)</h2>
<p>Sometimes your browser hands trying to load some heavy page, or a huge image or something else.<br />
You loose your time, your build lasts for a long; sessions get expired by timeout etc.</p>
<p>It would be reasonable to fail test fast in this case. But the default page loading timeout in Selenium is unreasonable big: the whole 5 minutes.</p>
<p>That’s why we added setting <code class="language-plaintext highlighter-rouge">Configuration.pageLoadTimeout</code>, so that you could easily change this timeout.</p>
<p>NB! The default is 30 seconds. It might be too small for your application. Be aware.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1268">issue 1268</a> and <a href="https://github.com/selenide/selenide/pull/1269">PR 1269</a>.</p>
<h2 id="we-added-generic-click-method-with-clickoptions-parameter">We added generic click method<br /> with <code class="language-plaintext highlighter-rouge">ClickOptions</code> parameter</h2>
<p>In a way, this is a new word in Selenide API.</p>
<p>Initially, Selenide has method <code class="language-plaintext highlighter-rouge">$.click()</code> which just called standard Selenium method <code class="language-plaintext highlighter-rouge">WebElement.click()</code>. Which clicks to the center of web element (I guess).</p>
<p>Over time, variations began to appear:</p>
<ul>
<li>we added setting <code class="language-plaintext highlighter-rouge">Configuration.clickViaJs</code> to click using JS code instead of <code class="language-plaintext highlighter-rouge">WebElement.click()</code>. In theory, it should make your tests more stable, and maybe even faster.</li>
<li>we added click with offset <code class="language-plaintext highlighter-rouge">$.click(offsetX, offsetY)</code> to click some other point but the center of element.</li>
</ul>
<p>But if you ever had need to click “both ways” (standard and via JS), you had to switch the global setting <code class="language-plaintext highlighter-rouge">Configuration.clickViaJs</code> every time. It might be inconvenient.</p>
<p>That’s why we added method <code class="language-plaintext highlighter-rouge">click</code> which accepts a “way to click” as an explicit parameter.</p>
<p>Now you can click in different ways without changing the global setting:</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! We recommend to set <code class="language-plaintext highlighter-rouge">Configuration.clickViaJs</code> to a value which is reasonable in most cases, and pass <code class="language-plaintext highlighter-rouge">ClickOptions</code> parameter only in exceptional cases.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1173">issue 1173</a>.<br />
Thanks to <a href="https://github.com/dstekanov">Dmytro Stekanov</a> for <a href="https://github.com/selenide/selenide/pull/1226">PR 1226</a>.</p>
<h2 id="we-added-generic-method-download-method-with-downloadoptions-parameter">We added generic method download method<br /> with <code class="language-plaintext highlighter-rouge">DownloadOptions</code> parameter</h2>
<p>A similar story is about method <code class="language-plaintext highlighter-rouge">$.download()</code>. Initially it could only download files with <code class="language-plaintext highlighter-rouge">GET</code> request.<br />
Later Selenide added possibility to download files via <code class="language-plaintext highlighter-rouge">PROXY</code> server. And recently we added a third way - <code class="language-plaintext highlighter-rouge">FOLDER</code>.<br />
Until now, you could only select the downloading method global, via global setting <code class="language-plaintext highlighter-rouge">Configuration.fileDownload</code>.</p>
<p>Now you can explicitly set downloading mode to every call of <code class="language-plaintext highlighter-rouge">$.download</code> method:</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! We recommend to set <code class="language-plaintext highlighter-rouge">Configuration.fileDownload</code> to a value which is reasonable in most cases, and pass <code class="language-plaintext highlighter-rouge">DownloadsOptions</code> parameter only in exceptional cases.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1259">issue 1259</a> and <a href="https://github.com/selenide/selenide/pull/1260">PR 1260</a>.</p>
<h2 id="we-added-methods-to-work-with-localstorage">We added methods to work with 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">// Delete all items from local storage:</span>
<span class="n">localStorage</span><span class="o">().</span><span class="na">clear</span><span class="o">();</span>
<span class="c1">// Add an item to local storage:</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">// Check item value:</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">// Check items count:</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">// Remove an item from local storage:</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>Thanks to <a href="https://github.com/dstekanov">Dmytro Stekanov</a> for <a href="https://github.com/selenide/selenide/pull/1274">PR 1274</a>.</p>
<h2 id="we-added-checks-for-element-own-text-without-descendants">We added checks for element own text (without descendants)</h2>
<p>The classical selenide check <code class="language-plaintext highlighter-rouge">$.shouldHave(text("Hello, world"))</code> includes text of element itself and all its children (descendants).<br />
But sometimes you want to check only the element itself, without descendants.</p>
<p>Now you can use <code class="language-plaintext highlighter-rouge">ownText</code> check for this:</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">// We expect element text to contain "Hello" world</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">// We expect element have text "Hello"</span>
</code></pre></div></div>
<p>See <a href="https://github.com/selenide/selenide/issues/1261">issue 1261</a> and <a href="https://github.com/selenide/selenide/pull/1262">PR 1262</a>.</p>
<h2 id="we-improved-performance-of-big-filtered-collections">We improved performance of big filtered collections</h2>
<p>Selenide has convenient methods for working with collections. You can search and filter elements, you can checks texts or properties of multiple elements with just one line.</p>
<p>But if you overuse this, you might end up with too slow tests. Like this:</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">// Page has 100 <li> elements</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"><</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>Assume that there is 100 <code class="language-plaintext highlighter-rouge"><li></code> elements on the page. Then this test can work too slowly, because:</p>
<ul>
<li>on each step, Selenide needs to reload the element (its state might have changed)</li>
<li>To reload Nth element of a collection, Selenide needs to reload the whole collection (Selenium does not have method like <code class="language-plaintext highlighter-rouge">WebDriver.findElement(index)</code>).</li>
<li>To reload a filtered collection, Selenide needs to apply the filter to all its elements (in this case, call <code class="language-plaintext highlighter-rouge">WebElement.isDisplayed()</code> for all 100 elements).</li>
</ul>
<p><br />
For comparison, this code works much faster:</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">// Unfiltered collection </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"><</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>In this release, we improved working we collections. Now Selenide filter for collections is a bit smarter: to get <code class="language-plaintext highlighter-rouge">list.get(N)</code>, it applies <code class="language-plaintext highlighter-rouge">visible</code> filter only to first <code class="language-plaintext highlighter-rouge"><N></code> elements, not to all 100 elements.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1266">issue 1266</a> and <a href="https://github.com/selenide/selenide/pull/1270">PR 1270</a>.</p>
<p><br />
P.S. Let me remind you another way to speed up working with collections - method <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() creates a "dump" of the collection. Selenide will not reload it </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"><</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>Method <code class="language-plaintext highlighter-rouge">$$.snapshot()</code> creates a “dump” of the collection. Selenide will not reload it every time.<br />
It makes your test much faster, but there is a risk to get <code class="language-plaintext highlighter-rouge">StaleElementReferenceException</code>, if the collection still changes during the iteration.</p>
<h2 id="we-added-check-href">We added check “href”</h2>
<p>Sometimes you want to check that element <code class="language-plaintext highlighter-rouge"><a></code> has a correct <code class="language-plaintext highlighter-rouge">href</code> attribute.<br />
Selenide has a method for attribute check: <code class="language-plaintext highlighter-rouge">$("a").shouldHave(attribute("href", "/foo/bar/details.html")</code>.</p>
<p>But there is a problem with links. Such a check may unexpectedly fail because Selenium returns an absolute, not a relative URL.</p>
<p>To address this issue, we added a special check for “href” attribute:</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>See <a href="https://github.com/selenide/selenide/issues/1272">issue 1272</a> and <a href="https://github.com/selenide/selenide/pull/1273">PR 1273</a>.</p>
<h2 id="we-added-chrome-option-no-sandbox">We added chrome option “–no-sandbox”</h2>
<p>We found that this option should make Chrome tests more stable. Let’s see if it helps.</p>
<p>See <a href="https://github.com/selenide/selenide/commit/3293956d">commit 3293956d</a></p>
<h2 id="now-selenide-throws-an-explicit-error">now Selenide throws an explicit error</h2>
<p>… if it failed to create downloads folder.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1265">issue 1265</a> and commit 94ece98f](https://github.com/selenide/selenide/commit/94ece98f).</p>
<h2 id="upgraded-to-webdrivermanager-422">Upgraded to WebDriverManager 4.2.2</h2>
<p>See <a href="https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md">WDM Changelog</a>.</p>
<p><br /></p>
<h2 id="news">News</h2>
<p>Exactly at the moment when I was releasing Selenide 5.15.0, Hima Bindu Peteti presented Selenide on meetup:</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=-FtWITInoCc&ab_channel=JoeColantonio">Test Automation Made Easy Using Selenide with Hima Bindu Peteti</a></li>
</ul>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.14.02020-08-17T00:00:00+00:00https://selenide.org/2020/08/17/selenide-5.14.0
<p>Good night!</p>
<p>We have released <a href="https://github.com/selenide/selenide/milestone/101?closed=1">Selenide 5.14.0</a>.</p>
<h2 id="stabilized-new-file-downloading-mode-folder">Stabilized new file downloading mode <code class="language-plaintext highlighter-rouge">FOLDER</code></h2>
<p>… which was introduced in <a href="/2020/07/08/selenide-5.13.0/">Selenide 5.13.0</a>.</p>
<p>What has been changed in 5.14.0:</p>
<ol>
<li>
<p>Every time when Selenide opens a browser it creates a unique downloads folder for it.<br />
It helps to avoid situation when parallel tests are downloading multiple files to the same folder at the same time.
And it’s impossible to understand what file is downloaded by which test.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1220">issue 1220</a> and <a href="https://github.com/selenide/selenide/pull/1221">PR 1221</a>.</p>
<ul>
<li>Unfortunately, it doesn’t work in IE and Safari (which don’t allow to customize downloads folder).</li>
<li>It works only for browsers opened by Selenide itself.</li>
<li>If you create browser by yourself, you will need to create the downloads folder and pass it to Selenide:
<ul>
<li>either using new method <code class="language-plaintext highlighter-rouge">setWebDriver(driver, proxy, downloadsFolder)</code>.</li>
<li>or constructor <code class="language-plaintext highlighter-rouge">SelenideDriver(..., downloadsFolder)</code>.</li>
</ul>
</li>
</ul>
</li>
<li>Before downloading next file, Selenide clears the downloads folder – see <a href="https://github.com/selenide/selenide/pull/1252">PR 1252</a></li>
<li>In the end of tests run, Selenide deletes all empty downloads folders – see <a href="https://github.com/selenide/selenide/pull/1247">PR 1247</a></li>
</ol>
<h2 id="added-check-shouldhaveitemwithtextany-text">Added check <code class="language-plaintext highlighter-rouge">$$.shouldHave(itemWithText("any text"))</code></h2>
<p>Unlike the classic check <code class="language-plaintext highlighter-rouge">$$.shouldHave(texts("text1", "text2"))</code>, it verifies that collection contains <strong>at least one
element with given text</strong>.</p>
<p>Thanks to <a href="https://github.com/LuisOsv">Luis Serna</a> for <a href="https://github.com/selenide/selenide/pull/1194">PR 1194</a>.</p>
<p>By the way, it’s the first commit to Selenide from Bolivia! :)</p>
<h2 id="added-support-for-safari-browser">Added support for Safari browser</h2>
<p>Few years ago Selenide already had Safari support, but it seemed to work badly at that time.<br />
At some moment, we removed the Safari support. <br />
Now it’s the next try. This time Safari tests seem to work more or less.</p>
<p>As usually, you need to add just one line to run tests in Safari:</p>
<ol>
<li><code class="language-plaintext highlighter-rouge">Configuration.browser = "safari";</code> or</li>
<li><code class="language-plaintext highlighter-rouge">-Dselenide.browser=safari</code></li>
</ol>
<p>Please share your feedback.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1236">issue 1236</a> and <a href="https://github.com/selenide/selenide/pull/1237">PR 1237</a>.</p>
<h2 id="added-method-selenidedriverscreenshotfilename">Added method <code class="language-plaintext highlighter-rouge">SelenideDriver.screenshot(fileName)</code></h2>
<p>It may be useful when you create “non-static” variant of driver (<code class="language-plaintext highlighter-rouge">new SelenideDriver()</code>) and want to take screenshots. <br />
Now you can do it.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1166">issue 1166</a> and <a href="https://github.com/selenide/selenide/pull/1227">PR 1227</a>.</p>
<h2 id="added-method-selenidedriverscreenshotoutputtype">Added method <code class="language-plaintext highlighter-rouge">SelenideDriver.screenshot(OutputType)</code></h2>
<p>Sometimes you need to get screenshot in Base64 format. For example, some visual comparison tools want it.</p>
<p>Now you can get screenshot as Base64 (or File or bytes) with new method <code class="language-plaintext highlighter-rouge">screenshot(OutputType)</code>:</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>See <a href="https://github.com/selenide/selenide/issues/1224">issue 1224</a> and <a href="https://github.com/selenide/selenide/pull/1231">PR 1231</a>.</p>
<h2 id="now-selenide-takes-a-screenshot-when-method-switchto-fails">Now Selenide takes a screenshot when method <code class="language-plaintext highlighter-rouge">switchTo()</code> fails</h2>
<p>As you know, Selenide automatically takes a screenshot in case of test failure. <br />
But we found that Selenide didn’t take a screenshot if one of these methods failed:</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>Now we fixed it.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1190">issue 1190</a> and <a href="https://github.com/selenide/selenide/pull/1240">PR 1240</a>.</p>
<h2 id="added-chrome-option---disable-dev-shm-usage">Added chrome option <code class="language-plaintext highlighter-rouge">--disable-dev-shm-usage</code></h2>
<p>We found that without this option, Chrome might sometimes crash (because of out of memory error).</p>
<ol>
<li>Why nobody complained about this?</li>
<li>Are thing better now after adding this option? Please share your feedback.</li>
</ol>
<p>P.S. Later some people <a href="https://github.com/selenide/selenide/issues/1559">complained</a> about this option. We are still investigating it.</p>
<h2 id="fixed-sizzle-selectors-on-web-pages-containing-dojojs-troopjs-etc">Fixed Sizzle selectors on web pages containing Dojo.js, troop.js etc.</h2>
<p>See <a href="https://github.com/selenide/selenide/issues/434">issue 434</a> and <a href="https://github.com/selenide/selenide/pull/1242">PR 1242</a>.</p>
<h2 id="made-method-tostring-safer">Made method <code class="language-plaintext highlighter-rouge">$.toString()</code> safer</h2>
<p>See <a href="https://github.com/selenide/selenide/issues/1241">issue 1241</a> and <a href="https://github.com/selenide/selenide/pull/1245">PR 1245</a>.</p>
<h2 id="improved-error-message-when-web-element-has-disappeared">Improved error message when web element has disappeared</h2>
<p>See <a href="https://github.com/selenide/selenide/issues/1013">issue 1013</a> and <a href="https://github.com/selenide/selenide/pull/1239">PR 1239</a>.</p>
<h2 id="upgraded-to-webdrivermanager-410">Upgraded to WebDriverManager 4.1.0</h2>
<p>See <a href="https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md">WDM Changelog</a>.</p>
<p><br /></p>
<h2 id="news">News</h2>
<ul>
<li>Wow! Udemy course including Selenide: “<a href="https://www.udemy.com/course/what-a-java-software-developer-must-know-about-testing/">What every java developer must know about software testing</a>”</li>
<li>A video about Selenide <a href="https://www.youtube.com/watch?v=WNzTuYFd8oI">in german</a></li>
<li>A project example <a href="https://github.com/d3m0/automation">using Selenide+Selenoid+Docker</a> by <a href="https://github.com/d3m0">d3m0</a></li>
<li>Another example: <a href="https://github.com/Crushpowerx/JavaMavenSelenideAllureScreenDiffExample">screenshot comparison using Selenide+Allure+Ashot+Screen Diff Plugin</a> by <a href="https://github.com/Crushpowerx/">Evgeniy Asovin</a></li>
<li>One more example: <a href="https://github.com/qaschevychelov/giphyTest">Selenide + Appium + Allure + TestNG</a> by <a href="https://github.com/qaschevychelov/">qaschevychelov</a></li>
<li>Selenide vs Selenium comparison: <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>Post by Jakub Skibiński in Sonalake company blog: <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://medium.com/@maxilect_pr/selenide-our-experience-11240f9ce10c">Switch from Serenity to Selenide</a> - 22.05.2020 by <a href="https://medium.com/@maxilect_pr">Yuri Kudryavtsev</a> (Maxilect company)</li>
</ul>
<p>And a bunch of posts by <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/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.13.02020-07-08T00:00:00+00:00https://selenide.org/2020/07/08/selenide-5.13.0
<p>Good morning!</p>
<p>Good summer!</p>
<p>We released <a href="https://github.com/selenide/selenide/milestone/98?closed=1">Selenide 5.13.0</a>.</p>
<p>Be prepared: it might break your tests (if they were not accurate).</p>
<ul class="blogpost-menu">
<li><a href="#should-have-empty-text">Forbidden <code class="language-plaintext highlighter-rouge">shouldHave(text(""))</code></a></li>
<li><a href="#remove-unneeded-allure-logs">Removed unneeded Allure logs</a></li>
<li><a href="#improve-collection-error-messages">Error messages for collections</a></li>
<li><a href="#fix-upload-without-form">Download files without <code class="language-plaintext highlighter-rouge"><form></code></a></li>
<li><a href="#download-files-with-quotes">Download files with quotes in name</a></li>
<li><a href="#write-webdriver-logs-to-file">Write webdriver logs to file</a></li>
<li><a href="#new-file-download-mode-folder">New downloading algorithm <code class="language-plaintext highlighter-rouge">FOLDER</code></a></li>
<li><a href="#get-wrapped-element-waits-for-element">Method <code class="language-plaintext highlighter-rouge">$.getWrappedElement()</code> waits for the element</a></li>
<li><a href="#statistics">Statistics</a></li>
</ul>
<h2 id="should-have-empty-text">Method <code class="language-plaintext highlighter-rouge">$.shouldHave(text(""))</code> now throws an exception</h2>
<p>Probably most popular Selenide method is <code class="language-plaintext highlighter-rouge">$.shouldHave(text("something"))</code>. But if you even use it daily, you might not
realize that it checks a <em>substring</em>, not the whole text.</p>
<p>So, a check <code class="language-plaintext highlighter-rouge">$("h1").shouldHave(text("ello"))</code> works even for element <code class="language-plaintext highlighter-rouge"><h1>Hello World</h1></code>.</p>
<p>A special case of this check is empty text: <code class="language-plaintext highlighter-rouge">$("h1").shouldHave(text(""))</code>. This check is <em>useless</em> becase
any string contains an empty substring.</p>
<blockquote>
<p>If you need to check that text is empty, you can use either <code class="language-plaintext highlighter-rouge">$("h1").shouldHave(exactText(""))</code> or <code class="language-plaintext highlighter-rouge">$("h1").shouldBe(empty)</code>.</p>
</blockquote>
<p>We want to help you overcome this typical problem and avoid useless checks. Now Selenide will throw an exception if
you pass null or empty string to method <code class="language-plaintext highlighter-rouge">text("")</code>.</p>
<blockquote>
<p>I tried Selenide 5.13.0 on my current project and found 20-30 tests that failed because of this new exception.<br />
All of this were logical errors in tests. You see what a useful change waits for you. :)</p>
</blockquote>
<p>See <a href="https://github.com/selenide/selenide/issues/1156">issue 1156</a>.<br />
Thanks to <a href="https://github.com/eaxdev">Roman S.A.</a> for <a href="https://github.com/selenide/selenide/pull/1186">PR 1186</a>.</p>
<p><strong>UPD</strong><br />
Later we added <a href="/2022/08/04/selenide-6.7.0/#holy-whole-string">setting <code class="language-plaintext highlighter-rouge">FULL_TEXT</code></a>,
that makes Selenide check the whole string, not a substring.</p>
<h2 id="remove-unneeded-allure-logs">Removed duplicated allure logs</h2>
<p>You might see that Selenide may logs the same action twice in some cases. For example, when executing this:</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>(actually this problem is not only in Allure reports, but also in usual Selenide <code class="language-plaintext highlighter-rouge">TextReport</code>)</p>
<p>Now we removed those duplicated logs. We had to refactor some code and change some other error messages, so be prepared.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/997">issue 997</a> and <a href="https://github.com/selenide/selenide/pull/1193">PR 1193</a>.</p>
<h2 id="improve-collection-error-messages">Improved error messages for collections</h2>
<p>Another story where we have changed error message format in case of search failure inside a collection.
I hope it should be clearer now what exactly Selenide failed to find.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/967">issue 967</a> and <a href="https://github.com/selenide/selenide/pull/1189">PR 1189</a>.</p>
<h2 id="fix-upload-without-form">Fixed uploading of files without <code class="language-plaintext highlighter-rouge"><form></code> tag</h2>
<p>As you probably know, Selenide allows uploading multiple files with one command:</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>To enable it, we once did a JS trick in Selenide.<br />
Now it appeared that this hack required <code class="language-plaintext highlighter-rouge"><input></code> to be inside of <code class="language-plaintext highlighter-rouge"><form></code>. This is reasonable, but for some reason
there are inputs that exist outside of <code class="language-plaintext highlighter-rouge"><form></code>. Our <code class="language-plaintext highlighter-rouge">$.uploadFile()</code> didn’t work for them.</p>
<p>Now we simplified upload implementation. Now it works for any inputs and doesn’t use JS tricks.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/943">issue 943</a> and <a href="https://github.com/selenide/selenide/pull/1188">PR 1188</a>.</p>
<h2 id="download-files-with-quotes">Fixed downloading files with quotation marks in the name</h2>
<p>… and other “bad” symbols.</p>
<p>It sounds strange, but sometimes people want to download files that have bad symbols in name (quotation marks, apostrophes etc).
Linux and Mac can save such files, but Windows cannot. Selenide method <code class="language-plaintext highlighter-rouge">$.download()</code> failed on Windows for such files.</p>
<p>Now method <code class="language-plaintext highlighter-rouge">$.download()</code> replaces quotation marks and other “bad” symbols in file name by underscore, as all major browsers do.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1196">issue 1196</a> and <a href="https://github.com/selenide/selenide/pull/1199">PR 1199</a>.</p>
<h2 id="write-webdriver-logs-to-file">Configured webdriver to write its logs to a file</h2>
<p>Until now, webdrivers started by Selenide didn’t write their logs to anywhere. You had to enable it explicitly if you needed them.</p>
<p>Now Selenide enables webdriver logs by default. They are written to file like <code class="language-plaintext highlighter-rouge">build/reports/tests/webdriver.ts_pid_tid.log</code>.<br />
You can get full file name from Selenide logs like this:</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>Read these logs next time when you need to debug some weird webdriver behaviour.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1206">issue 1206</a> and <a href="https://github.com/selenide/selenide/pull/1207">PR 1207</a>.</p>
<h2 id="new-file-download-mode-folder">Added new way of downloading files: <code class="language-plaintext highlighter-rouge">FOLDER</code></h2>
<p>As you probably know, Selenide has 2 options for downloading files: <code class="language-plaintext highlighter-rouge">HTTPGET</code> and <code class="language-plaintext highlighter-rouge">PROXY</code>.<br />
See <a href="/2019/12/10/advent-calendar-download-files/">post in our blog</a>.</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">HTTPGET</code> - simple and stable. But it can only download files using links like <code class="language-plaintext highlighter-rouge"><a href></code>.</li>
<li><code class="language-plaintext highlighter-rouge">PROXY</code> - generic and powerful. But it may cause problems if you run browser remotely because it requires access from “browser machine” to “tests machine”.
It often causes troubles for Selenoid and Grid users.</li>
</ul>
<p>Now we have a third option: <code class="language-plaintext highlighter-rouge">FOLDER</code>.</p>
<p>To use it, just add this line in the beginning of tests:</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>It’s working mechanism is very simple:</p>
<ol>
<li>It clicks the element,</li>
<li>Watches for new files in folder <code class="language-plaintext highlighter-rouge">build/downloads</code></li>
<li>If there are several new files, tries to guess which one if them suites better.</li>
</ol>
<p>As always, you can find a working example <a href="https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/FileDownloadToFolderTest.java">in Selenide own tests</a>.</p>
<p><br />
P.S. We consider this option <em>experimental</em> by now because there are some nuances:</p>
<ol>
<li>It works well on local run with single browser, but</li>
<li>During parallel run, multiple browsers might download their files into the same folder, and then Selenide might pick a wrong file.</li>
<li>During remote run, this option doesn’t work at all. Tests are on machine A, but browser and files are on machine B.</li>
<li>Currently only Chrome, Firefox, Edge, Opera are supported. But IE and Safari are not: they don’t allow to configure the downloads folder.</li>
</ol>
<p>We will work on those nuances. Please share your thoughts on how can we solve them.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1212">issue 1212</a>,
<a href="https://github.com/selenide/selenide/pull/1213">PR 1213</a> and
<a href="https://github.com/selenide/selenide/pull/1215">PR 1215</a>.</p>
<p>UPD Later we improved method <code class="language-plaintext highlighter-rouge">FOLDER</code>, and now you can safely use it in your projects.</p>
<h2 id="get-wrapped-element-waits-for-element">Method <code class="language-plaintext highlighter-rouge">$.getWrappedElement()</code> waits for the element. Again.</h2>
<p>Probably it doesn’t affect you, but I have to mention it. Essentially, we reverted one recent change (made in Selenide 5.11).</p>
<p>Assuming you have the following code:</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>where <code class="language-plaintext highlighter-rouge">button</code> is shown <em>with a delay</em>.</p>
<p>Selenide always waits for this <code class="language-plaintext highlighter-rouge">button</code> to appear, and only then executed the JS code.<br />
In Selenide 5.11 we did a change, so that Selenide didn’t wait for the <code class="language-plaintext highlighter-rouge">button</code> anymore.<br />
It could break some tests which occasionally relied on that behaviour. <br />
Now we restored that old behaviour: Selenide waits for the <code class="language-plaintext highlighter-rouge">button</code> again before executing JS code.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1191">issue 1191</a> and <a href="https://github.com/selenide/selenide/pull/1203">PR 1203</a>.</p>
<h2 id="upgrade-to-bup-2.1.1">Upgraded to BrowserUpProxy 2.1.1</h2>
<p>Just in case</p>
<p>Upgrade. Try. Share you feedback.</p>
<h2 id="statistics">Statistics</h2>
<p>And here is my favorite part: latest Selenide downloads statistics.<br />
We hit the line <strong>160 thousands per months</strong>!</p>
<center>
<img src="/images/2020/07/selenide.downloads.png" width="800" />
</center>
<p><br /></p>
<p>and <strong>31+ thousands of unique IPs</strong>:</p>
<center>
<img src="/images/2020/07/selenide.unique-ips.png" width="800" />
</center>
<p>Life is good!</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.12.22020-05-29T00:00:00+00:00https://selenide.org/2020/05/29/selenide-5.12.2
<p>Hi all!</p>
<p>We have published one more mini-release <a href="https://github.com/selenide/selenide/milestone/99?closed=1">Selenide 5.12.2</a>.</p>
<h2 id="fixed-annotations-nonnull">Fixed annotations @Nonnull</h2>
<p>… for some of <code class="language-plaintext highlighter-rouge">SelenideElement</code> methods.</p>
<p>After upgrading to Selenide 5.12.0 some Kotlin users started getting compilation errors in their projects. <br />
It’s because we marked all methods of <code class="language-plaintext highlighter-rouge">SelenideElement</code> with annotations <code class="language-plaintext highlighter-rouge">@Nullable</code>/<code class="language-plaintext highlighter-rouge">@Nonnull</code>, and Kotlin is sensible to them.</p>
<p>For the following methods we now changed <code class="language-plaintext highlighter-rouge">@Nullable</code> annotation to <code class="language-plaintext highlighter-rouge">@Nonnull</code> (because they never return 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>Now you can again put results of those methods to non-nullable variables (though such constructs seem to me a bit strange in tests).</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1179">issue 1179</a> and <a href="https://github.com/selenide/selenide/pull/1181">PR 1181</a>.</p>
<h2 id="fixed-setting-holdbrowseropentrue">Fixed setting <code class="language-plaintext highlighter-rouge">holdBrowserOpen=true</code></h2>
<p>This setting didn’t work sometimes.<br />
No we fixed it.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1172">issue 1172</a> and <a href="https://github.com/selenide/selenide/pull/1176">PR 1176</a>.</p>
<h2 id="news">News</h2>
<p>Wow!</p>
<p>It happened!!!</p>
<p>We published <a href="https://github.com/selenide/selenide-for-selenium-ide">Selenium IDE plugin</a> which can <strong>export code to Selenide</strong>.</p>
<ul>
<li><a href="https://chrome.google.com/webstore/detail/selenide-for-selenium-ide/nlkfobhoffngaakgdbkdnmmjcchibcba">for Chrome</a></li>
<li><a href="https://addons.mozilla.org/ru/firefox/addon/selenide-for-selenium-ide/">for Firefox</a></li>
</ul>
<p>We will publish a separate post soon on this topic.</p>
<p>Huge thanks to <a href="https://github.com/dstekanov">Dmytro Stekanov</a> for this historical moment for Selenide!</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.12.12020-05-25T00:00:00+00:00https://selenide.org/2020/05/25/selenide-5.12.1
<p>Good night!</p>
<p>This is a quickfix release <a href="https://github.com/selenide/selenide/milestone/97?closed=1">Selenide 5.12.1</a>
with a couple of minor fixes for <a href="/2020/05/23/selenide-5.12.0/">Selenide 5.12.0</a></p>
<h2 id="fixed-concurrent-modification-exception-during-webdriver-initialization">Fixed <em>Concurrent modification exception</em> during webdriver initialization</h2>
<p>See <a href="https://github.com/selenide/selenide/issues/1170">issue 1170</a> and <a href="https://github.com/selenide/selenide/pull/1171">PR 1171</a>.</p>
<h2 id="fixed-merging-of-excludeswitches-settings-of-different-types">Fixed merging of “excludeSwitches” settings of different types</h2>
<p>It appeared that setting <code class="language-plaintext highlighter-rouge">excludeSwitches</code> can have either Array or List type:</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>Selenide 5.12.0 crashed if both of types were used. Now we fixed it.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1169">issue 1169</a> and <a href="https://github.com/selenide/selenide/pull/1174">PR 1174</a>.</p>
<h2 id="news">News</h2>
<ul>
<li>We published <a href="https://github.com/selenide/selenide/wiki/Selenide-Roadmap">Selenide Roadmap</a>. Feel free to share your feedback!</li>
<li>Vide from <a href="https://www.youtube.com/watch?v=1d-nKyeTH2Y">pro:TEST meetup</a> - Czech, 28.04.2020</li>
<li>Video from <a href="https://www.youtube.com/watch?v=aFqZ6dbUJIw&feature=emb_logo">QA meetup</a> - Slovak, 12.05.2020</li>
</ul>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.12.02020-05-23T00:00:00+00:00https://selenide.org/2020/05/23/selenide-5.12.0
<p>Good day!</p>
<p>Yes! We released <a href="https://github.com/selenide/selenide/milestone/95?closed=1">Selenide 5.12.0</a>.</p>
<p>Most of the changes are about browser capabilities.</p>
<h2 id="we-fixed-an-old-problem-with-configurationbrowsercapabilities">We fixed an old problem with <code class="language-plaintext highlighter-rouge">Configuration.browserCapabilities</code></h2>
<p>People had been complaining for years about <code class="language-plaintext highlighter-rouge">ChromeOptions</code>: some of these settings could be lost in some circumstances. <br />
It was caused by <a href="https://github.com/SeleniumHQ/selenium/issues/5279">an old bug in Selenium webdriver</a>, which seems to be lost and forgotten.</p>
<p>But it seems that we have found a simple workaround for this problem.</p>
<ul>
<li>If it helped you - please share you feedback.</li>
<li>If it didn’t help - please register a github issue. We will work out another hack. :)</li>
</ul>
<p>See <a href="https://github.com/selenide/selenide/issues/676">issue 676</a>, <a href="https://github.com/selenide/selenide/issues/1097">issue 1097</a>
and <a href="https://github.com/selenide/selenide/pull/1155">PR 1155</a>.</p>
<p>Special thanks to those experiments that didn’t get to the release, but inspired it:</p>
<ul>
<li>Thanks to <a href="https://github.com/BorisOsipov">Boris Osipov</a> for <a href="https://github.com/selenide/selenide/pull/1103">PR #1103</a></li>
<li>Thanks to <a href="https://github.com/SeleniumTestAB">SeleniumTestAB</a> for <a href="https://github.com/selenide/selenide/pull/1095">PR #1095</a></li>
</ul>
<h2 id="we-disabled-to-annoying-dialog-save-password">We disabled to annoying dialog “save password?”</h2>
<p>See <a href="https://github.com/selenide/selenide/issues/1133">issue 1133</a> and <a href="https://github.com/selenide/selenide/pull/1134">PR 1134</a>.</p>
<h2 id="we-adeed-mobile-emulation-mode-in-grid">We adeed “mobile emulation” mode in grid</h2>
<p>Since Selenide 5.6.1, you can run Chrome in “mobile emulation” mode:</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>Recently we found that this option only works when running Chrome locally, and was not passed to the remote Chrome.<br />
Now we fixed it: when running Chrome in Grid, we pass all options that are used for local Chrome (except “downloads folder”).</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1109">issue 1109</a> and <a href="https://github.com/selenide/selenide/pull/1163">PR 1163</a>.</p>
<h2 id="we-simplified-firefox-setup-now-without-profile">We simplified Firefox setup: now without profile</h2>
<p>When opening a Firefox browser, Selenide created a new profile (<code class="language-plaintext highlighter-rouge">FirefoxProfile</code>) - at least to set a “downloads folder” setting.<br />
Recently we found that using profile causes some limitations, and generally is not needed (I guess profile was needed for the legacy firefox driver).</p>
<p>Now we don’t create a profile by default.</p>
<ol>
<li>Instead, we set downloads folder via <code class="language-plaintext highlighter-rouge">firefoxOptions.addPreference("browser.download.dir")</code>.</li>
<li>We only create profile if you set some system settings starting with <code class="language-plaintext highlighter-rouge">"firefoxprofile."</code>.</li>
</ol>
<p>See <a href="https://github.com/selenide/selenide/issues/1139">issue 1139</a> and <a href="https://github.com/selenide/selenide/pull/1165">PR 1165</a>.</p>
<h2 id="we-set-accept_insecure_certs-setting-for-chromium-based-edge-versions">We set <code class="language-plaintext highlighter-rouge">"ACCEPT_INSECURE_CERTS"</code> setting for chromium-based Edge versions</h2>
<p>Starting from some version, IE and Edge browser stopped supporting <code class="language-plaintext highlighter-rouge">"ACCEPT_INSECURE_CERTS"</code> setting<br />
(which enables self-signed SSL certificates). So we removed this setting for IE and Edge (starting from Selenide 5.9.0).</p>
<p>Recently we found that latest versions of Edge browser (which are built on Chromium engine) do support this setting. <br />
So we set <code class="language-plaintext highlighter-rouge">"ACCEPT_INSECURE_CERTS"</code> again for Edge 75 and newer.</p>
<p>NB! Selenide can know Edge version only if EdgeDriver was downloaded with WebDriverManager (which is enabled by default in Selenide).</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1093">issue 1093</a> and <a href="https://github.com/selenide/selenide/pull/1167">PR 1167</a>.</p>
<h2 id="we-upgraded-to-webdrivermanager-400">We upgraded to WebDriverManager 4.0.0</h2>
<ul>
<li>Support for Firefox 76</li>
<li>Support for Edge 81, 83, 84</li>
<li>Upgraded Apache HttpClient from 4.x to 5.0</li>
</ul>
<p>See <a href="https://github.com/selenide/selenide/pull/1149">PR 1149</a> and <a href="https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md">WDM Changelog</a>.</p>
<h2 id="we-upgraded-to-browserup-proxy-core210">We upgraded to browserup-proxy-core:2.1.0</h2>
<p>Just in case.</p>
<h2 id="we-fixed-name-of-screenshot-folder-emptymethod">We fixed name of screenshot folder ‘emptyMethod’</h2>
<p>This issue was specific to JUnit 5.</p>
<p>Thanks to <a href="https://github.com/dengayevskiy-sb">Denis Gaievsky</a> for <a href="https://github.com/selenide/selenide/pull/1138">PR 1138</a>.</p>
<h2 id="annotated-most-of-the-public-selenide-methods-with-nullable-and-nonnull">Annotated most of the public Selenide methods with <code class="language-plaintext highlighter-rouge">@Nullable</code> and <code class="language-plaintext highlighter-rouge">@Nonnull</code></h2>
<p>It will help IDEA (and hopefully other IDEs) to better highlight issues in your tests. <br />
It will also help Kotlin users to use nullable/non-nullable types.</p>
<p>Again, thanks to <a href="https://github.com/jreznot">Yuriy Artamonov</a> for
<a href="https://github.com/selenide/selenide/pull/1140">PR 1140</a> and <a href="https://github.com/selenide/selenide/pull/1144">PR 1144</a>!</p>
<h2 id="news">News</h2>
<ul>
<li>We published <a href="https://github.com/selenide/selenide/wiki/Selenide-Roadmap">Selenide Roadmap</a>. Feel free to share your feedback!</li>
<li>Vide from <a href="https://www.youtube.com/watch?v=1d-nKyeTH2Y">pro:TEST meetup</a> - Czech, 28.04.2020</li>
<li>Video from <a href="https://www.youtube.com/watch?v=aFqZ6dbUJIw&feature=emb_logo">QA meetup</a> - Slovak, 12.05.2020</li>
</ul>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.11.12020-04-21T00:00:00+00:00https://selenide.org/2020/04/21/selenide-5.11.1
<p>Good evening!</p>
<p>It seems that <a href="https://github.com/selenide/selenide/milestone/94?closed=1">Selenide 5.11.0</a> still broke too many rules,
and we decided to slow down the horses.</p>
<p>If you are affected, you can upgrade to <a href="https://github.com/selenide/selenide/milestone/96?closed=1">Selenide 5.11.1</a>.</p>
<h2 id="slf4j">SLF4J</h2>
<p>Some folks didn’t like the fact that Selenide 5.11.0 requires a valid slf4j dependency. Folks don’t want to
bother with slf4j. Folks don’t want to read our logs. :)</p>
<p>It was unexpected for us, but well, we found a compromise.</p>
<p>Now Selenide doesn’t require slf4j always, but only when it’s needed for sure. Namely, when you use
<a href="/2016/09/26/selenide-3.10/"><code class="language-plaintext highlighter-rouge">TextReport</code> feature</a>.</p>
<h2 id="because-we-can">because we can!</h2>
<p>In Selenide 5.11.0 we introduced one small issue. Namely,</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">$("blah").shouldNot(exist)</code> - passes (it’s ok)</li>
<li><code class="language-plaintext highlighter-rouge">$("blah").shouldNot(exist.because("we can"))</code> - fails (it’s not ok)</li>
</ul>
<p>Word <code class="language-plaintext highlighter-rouge">because</code> happened to be incompatible with negation. Now we fixed it, and both lines are passing.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1130">issue 1130</a> and <a href="https://github.com/selenide/selenide/pull/1131">1131</a>.</p>
<h2 id="dropped-16-megabytes">Dropped 16 megabytes</h2>
<p>It appears that Selenide had one huge 16 megabyte sized file <code class="language-plaintext highlighter-rouge">checker.jar</code> among its dependencies.<br />
Now we removed it.</p>
<p>Thanks to <a href="https://github.com/jreznot">Yuriy Artamonov</a> for <a href="https://github.com/selenide/selenide/pull/1128">PR 1128</a>.</p>
<h2 id="news">News</h2>
<p>I will present Selenide on Czech meetup <a href="https://www.meetup.com/protest_cz/events/270022839/">[pro:]TEST!</a> next Tuesday, 28.04.2020.<br />
This is an online event, so everybody can participate for free. You can call your friends who is not familiar with Selenide yet!</p>
<ul>
<li>Language: English</li>
<li>Date: 28.04.2020, 18:00 GMT+2</li>
<li>Level: rather for beginners</li>
<li>Links: <a href="https://bit.ly/protest84invitation">Announcement</a> / <a href="https://www.youtube.com/watch?v=1d-nKyeTH2Y&feature=youtu.be">Live stream</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>See you online!</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.11.02020-04-19T00:00:00+00:00https://selenide.org/2020/04/19/selenide-5.11.0
<p>Good night!</p>
<p>We have released <a href="https://github.com/selenide/selenide/milestone/94?closed=1">Selenide 5.11.0</a>.<br />
This is the second quarantine release of Selenide in which we made a couple of breaking changes.</p>
<h2 id="changed-the-behaviour-of-shouldnot-methods-for-unexisting-elements">Changed the behaviour of <code class="language-plaintext highlighter-rouge">shouldNot*</code> methods for unexisting elements</h2>
<p>Just look at the table below to understand what changed.<br />
Assuming element <code class="language-plaintext highlighter-rouge">h1</code> <strong>does not exist</strong> on a page:</p>
<table>
<thead>
<tr>
<th>Check</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>
<h3 id="previous-logic">Previous logic</h3>
<p>A long time ago it was decided in Selenide: the check <code class="language-plaintext highlighter-rouge">h1.shouldNotHave(text("foo"))</code> should not fail. If the element <code class="language-plaintext highlighter-rouge"><h1></code>
does not exist, then it doesn’t have text “foo”. So, the condition “should not have text” is true.</p>
<p>Additionally, it seemed to be reasonable because the check <code class="language-plaintext highlighter-rouge">h1.shouldNotHave(text("foo"))</code> is the opposite to
<code class="language-plaintext highlighter-rouge">h1.shouldHave(text("foo"))</code> which fails for an unexisting element.</p>
<h3 id="new-logic">New logic</h3>
<p>But we realized that there was a problem with the previous approach: it allowed to make a mistake too easily.
Namely, you could accidentally write a wrong locator, thus making a false-positive test. Test that was green, but didn’t check anything.</p>
<p>Now both <code class="language-plaintext highlighter-rouge">h1.shouldHave(text("foo"))</code> and <code class="language-plaintext highlighter-rouge">h1.shouldNotHave(text("foo"))</code> fail if <code class="language-plaintext highlighter-rouge"><h1></code> is not found.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/368">issue 368</a> and <a href="https://github.com/selenide/selenide/pull/1116">PR 1116</a>.</p>
<h2 id="now-selenide-fails-if-slf4j-is-not-configured">Now Selenide fails if SLF4J is not configured</h2>
<p>If you get such an error:</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>don’t be afraid: just do what it says. It’s easy.</p>
<h4 id="what-problem-we-tried-to-solve">What problem we tried to solve?</h4>
<p>The problem is: if you don’t have any SLF4J implementations in your project, you could miss some important Selenide
logs, including “text report”. Now you are forced to include some of SLF4J implementations.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1114">issue 1114</a> and <a href="https://github.com/selenide/selenide/pull/1115">PR 1115</a>.</p>
<h2 id="added-method-for-partially-checking-the-attribute-value">Added method for <em>partially</em> checking the attribute value</h2>
<p>Until now, Selenide had 2 methods for checking attributes:</p>
<ol>
<li>presence of attribute, and</li>
<li>exact value of attribute:</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>Now we added method <code class="language-plaintext highlighter-rouge">attributeMatching</code> for <em>partially</em> checking attribute value.<br />
See examples <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/AttributeTest.java">in tests</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>See <a href="https://github.com/selenide/selenide/issues/996">issue 996</a>.<br />
Thanks to <a href="https://github.com/dstekanov">Dmytro Stekanov</a> for <a href="https://github.com/selenide/selenide/pull/1100">PR 1100</a>.</p>
<h2 id="added-method-for-getting-the-last-screenshot">Added method for getting the last screenshot</h2>
<p>We added 2 new methods:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">Screenshots.getLastThreadScreenshot()</code> - returns the last screenshot taken in current thread</li>
<li><code class="language-plaintext highlighter-rouge">Screenshots.getThreadScreenshots()</code> - returns all screenshots taken in current thread</li>
</ul>
<p>Most of the users <strong>do not need</strong> those methods: Selenide adds screenshot details to error message anyway. <br />
But those methods can be useful for those who write their own frameworks on top of Selenide or integrate Selenide
with frameworks like Allure.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1029">issue 1029</a>.<br />
Thanks to <a href="https://github.com/dstekanov">Dmytro Stekanov</a> for <a href="https://github.com/selenide/selenide/pull/1125">PR 1125</a>.</p>
<h2 id="added-annotation-checkreturnvalue-to-most-of-selenide-methods">Added annotation <code class="language-plaintext highlighter-rouge">@CheckReturnValue</code> to most of Selenide methods</h2>
<p>It allows IDE (at least Intellij IDEA) to better analyze your tests and show warnings if you called some Selenide
method, but forgot to check results:</p>
<center>
<img src="/images/2020/04/idea-warning.png" width="500" />
</center>
<p>Thanks to <a href="https://github.com/jreznot">Yuriy Artamonov</a> for <a href="https://github.com/selenide/selenide/pull/1106">PR 1106</a>.</p>
<h2 id="added-missing-method-selectorsbytagname">Added missing method <code class="language-plaintext highlighter-rouge">Selectors.byTagName()</code></h2>
<p>Just for consistency with <code class="language-plaintext highlighter-rouge">By</code> methods.</p>
<p>Thanks to <a href="https://github.com/jreznot">Yuriy Artamonov</a> for <a href="https://github.com/selenide/selenide/pull/1104">PR 1104</a>.</p>
<h2 id="fixed-screenshot-url">Fixed screenshot URL</h2>
<p>… in case when project is run in Jenkins, and the project path contains spaces.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1072">issue 1072</a>.<br />
Thanks to <a href="https://github.com/dstekanov">Dmytro Stekanov</a> for <a href="https://github.com/selenide/selenide/pull/1098">PR 1098</a>.</p>
<h2 id="disabled-annoying-warnings-about-chrome-extensions">Disabled annoying warnings about Chrome extensions</h2>
<p>Some folks saw those annoying warnings in Chrome:</p>
<center>
<img src="/images/2020/04/chrome-warning.png" width="300" />
</center>
<p>Now we disabled them with this setting:</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>Please let us know if it causes some problems in your projects.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1119">issue 1119</a> and <a href="https://github.com/selenide/selenide/pull/1120">PR 1120</a>.</p>
<h2 id="now-you-can-set-selectormode-and-assertionmode-via-system-properties">Now you can set <code class="language-plaintext highlighter-rouge">selectorMode</code> and <code class="language-plaintext highlighter-rouge">assertionMode</code> via system properties</h2>
<p>… Just for consistency with other Selenide settings.</p>
<p>See <a href="https://github.com/selenide/selenide/commit/231597eb6229e">commit 231597eb6229e</a>.</p>
<h2 id="method-getwrappedelement-doesnt-wait-anymore">Method <code class="language-plaintext highlighter-rouge">$.getWrappedElement()</code> doesn’t wait anymore</h2>
<p>I guess most of you didn’t even know about this method.<br />
A long time ago, it was added to give access to the original Selenium <code class="language-plaintext highlighter-rouge">WebElement</code> without any Selenide magic (just in case, if somebody should need it).<br />
But <a href="https://github.com/yashaka">Iakiv Kramarenko</a> noticed that it still applies Selenide magic: method <code class="language-plaintext highlighter-rouge">$.getWrappedElement()</code> waited for presence of the <code class="language-plaintext highlighter-rouge">WebElement</code>.</p>
<p>Not it doesn’t wait anymore. If the element doesn’t exist - you will get <code class="language-plaintext highlighter-rouge">org.openqa.selenium.NoSuchElementException</code>.<br />
And yes, you can also get the legendary <code class="language-plaintext highlighter-rouge">StaleElementReferenceException</code>.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1015">issue 1015</a> and <a href="https://github.com/selenide/selenide/pull/1124">PR 1124</a>.</p>
<h2 id="statistics">Statistics</h2>
<p>And here is my favorite part: latest Selenide downloads statistics. We hit the line 130 thousands per months!</p>
<center>
<img src="/images/2020/04/selenide.downloads.png" width="800" />
</center>
<p><br /></p>
<p>and 23 thousands of unique IPs:</p>
<center>
<img src="/images/2020/04/selenide.unique-ips.png" width="800" />
</center>
<p>Life is good!</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.10.02020-03-18T00:00:00+00:00https://selenide.org/2020/03/18/selenide-5.10.0
<p>Good quarantine!</p>
<p>It was the third day of quarantine.</p>
<p>To make you feel not so lonely, we released <a href="https://github.com/selenide/selenide/milestone/93?closed=1">Selenide 5.10.0</a> with
a bunch of improvements. Some of them are even slightly backward incompatible. Well, so you do not get bored in your dens.</p>
<ul>
<li><a href="#add-shadow-dom-support">Added support for Shadow DOM</a></li>
<li><a href="#exclude-bup-by-default">Don’t fetch BrowserUpProxy by default</a></li>
<li><a href="#replace-guava">Replace Guava APIs by Java APIs</a></li>
<li><a href="#add-quotes-to-report">Made Selenide Allure report nicer</a></li>
<li><a href="#add-image-condition">Added condition shouldBe(image)</a></li>
<li><a href="#video">Videos</a></li>
</ul>
<h2 id="add-shadow-dom-support">We added support for Shadow DOM</h2>
<p>See examples <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/ShadowElementTest.java">in tests</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>: Calling <code class="language-plaintext highlighter-rouge">setValue("text")</code> / <code class="language-plaintext highlighter-rouge">val("text")</code> on an input field will result in an error, saying that the element is “not reachable by keyboard”. <br />
Temporary workaround for now is to use <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>See <a href="https://github.com/selenide/selenide/issues/1014">issue 1014</a>.<br />
Thanks to <a href="https://github.com/dstekanov">Dmytro Stekanov</a> for <a href="https://github.com/selenide/selenide/pull/1090">PR 1090</a>.</p>
<h2 id="exclude-bup-by-default">Selenide does not fetch BrowserUpProxy by default</h2>
<p>Taking those two facts into account:</p>
<ol>
<li>Selenide fetches BrowserUpProxy and all its transitive dependencies - it’s about ~17MB in total.</li>
<li>Most of Selenide users (I guess) do not use Selenide proxy.</li>
</ol>
<p>we decided to avoid fetching those 17 megabytes by default.</p>
<h3 id="the-dependency">The dependency</h3>
<p>Those of you who wants to use proxy just need to add a dependency to your project:</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>(many of you already have it anyway).</p>
<p>Don’t worry if you forget to add the dependency - you will see a clear error message like this:</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>See <a href="https://github.com/selenide/selenide/issues/1021">issue 1021</a> and <a href="https://github.com/selenide/selenide/pull/1094">PR 1094</a>.</p>
<p><strong>UPD 12.03.2023</strong>
Nowadays we don’t need to add that dependency anymore. Just use <code class="language-plaintext highlighter-rouge">com.codeborne:selenide-proxy</code> instead of <code class="language-plaintext highlighter-rouge">com.codeborne:selenide</code>.
It will add all needed dependencies automatically.</p>
<h3 id="just-in-case">Just in case</h3>
<p>Probably you feel curious who eats those 17 megabytes? Here they are. <br />
This is the list of files that should disappear from your project. The list is impressive, right?</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><br /></p>
<h2 id="replace-guava">Migrated Guava API to corresponding Java API</h2>
<p>We just changed</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">com.google.common.base.Predicate</code> from Guava</li>
<li>to <code class="language-plaintext highlighter-rouge">java.util.function.Predicate</code> from Java 8</li>
</ul>
<p>and removed Guava dependency. It was great (until Java 8 was released), rip.</p>
<p>If you occasionally implemented your own <code class="language-plaintext highlighter-rouge">CollectionCondition</code>, you will need to rename <code class="language-plaintext highlighter-rouge">apply</code> to <code class="language-plaintext highlighter-rouge">test</code>. It must be easy.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1091">issue 1091</a>.<br />
Thanks to <a href="https://github.com/wlsc">Wladimir Schmidt</a> for <a href="https://github.com/selenide/selenide/pull/1091">PR 1091</a>.</p>
<p><br /></p>
<h2 id="add-quotes-to-report">We made Selenide Allure report a little nicer</h2>
<p>We actually just added quotes around selectors in the Allure report.<br />
Now you can copy selectors from the report and paste into browser’s developer console (though, I cannot imagine why somebody should do it).</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1032">issue 1032</a>.<br />
Thanks to <a href="https://github.com/dstekanov">Dmytro Stekanov</a> for <a href="https://github.com/selenide/selenide/pull/1092">PR 1092</a>.</p>
<p><br /></p>
<h2 id="add-image-condition">We added condition <code class="language-plaintext highlighter-rouge">$("img").shouldBe(image)</code></h2>
<p>You can use it to check that image was successfully loaded.</p>
<p>See examples <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/ImageTest.java">in tests</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>See <a href="https://github.com/selenide/selenide/issues/1069">issue 1069</a>.<br />
Thanks to <a href="https://github.com/dstekanov">Dmytro Stekanov</a> for <a href="https://github.com/selenide/selenide/pull/1086">PR 1086</a>.</p>
<p><br /></p>
<h2 id="fix-search-by-attribute-with-quotes">We fixed find element by attribute which contains quites</h2>
<p>For some reason, people sometimes put quotes inside attributes.<br />
When trying to find an element by such an attribute, Selenide generated an invalid CSS locator.<br />
Now we fixed it.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1060">issue 1060</a>.<br />
Thanks to <a href="https://github.com/denysLystopadskyy">Denys Lystopadskyy</a> for <a href="https://github.com/selenide/selenide/pull/1062">PR 1062</a>.</p>
<p><br /></p>
<h2 id="video">Videos</h2>
<p>Did you think that probably SeleniumCamp 2020 is The Last Conference on Earth?</p>
<p>Because of quarantine, they have published all <a href="https://www.youtube.com/playlist?list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe">SeleniumCamp 2020 videos</a>.</p>
<p>Among others, this playlist contains my 3 videos (sorry, they are in Russian):</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=6MfMtky-0q4&list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe&index=35">Flaky tests: The method</a></li>
<li><a href="https://www.youtube.com/watch?v=RmaTYY3B-Wg&list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe&index=41">BOF: Glorious past and promising future of Selenide</a></li>
<li><a href="https://www.youtube.com/watch?v=4vI4Z6sE7OA&list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe&index=16">Threesome: Selenide for Web, Android and iOS</a></li>
</ul>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.9.02020-03-10T00:00:00+00:00https://selenide.org/2020/03/10/selenide-5.9.0
<p>Buenos Marchos!</p>
<p>In Selenide, we strive to cure flaky tests all the time.</p>
<p>Today we released <a href="https://github.com/selenide/selenide/milestone/92?closed=1">Selenide 5.9.0</a> with one feature that can help to overcome some of your flaky tests.</p>
<h2 id="we-added-a-filter-for-downloading-files-downloadfilefilter">We added a filter for downloading files: <code class="language-plaintext highlighter-rouge">$.download(FileFilter)</code></h2>
<h3 id="problem">Problem</h3>
<p>When downloading files <em>via proxy</em>, Selenide can sometimes download a wrong file. <br />
This is how it works: Selenide clicks the “download” button and intercepts all responses from server to browser.</p>
<p>Exactly at this moment there could happen some unrelated requests between browser and server.<br />
Say, chrome decides to check for updates at this moment. Or your AUT sends request to google analytics. Or just some background requests. <br />
This creates fertile ground for emergence of <em>flaky tests</em> which work on your machine but sometimes fail on jenkins.</p>
<h3 id="solution">Solution</h3>
<p>To avoid such collisions, you can now explicitly specify which file you expect.
Out of the box, there are filters by file name or extension. And you can create your own
<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> implementations with
any filters you need.<br />
Given such a filter, Selenide will select the right response matching your criteria.</p>
<p>See examples <a href="https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/FileDownloadViaProxyTest.java">in tests</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>See <a href="https://github.com/selenide/selenide/issues/1065">issue 1065</a> and <a href="https://github.com/selenide/selenide/pull/1080">PR 1080</a>.</p>
<h2 id="we-fixed-error-when-starting-ie-3150">We fixed error when starting IE 3.150</h2>
<p>See <a href="https://github.com/selenide/selenide/issues/1061">issue 1061</a>.<br />
Thanks to <a href="https://github.com/BorisOsipov">Boris Osipov</a> for <a href="https://github.com/selenide/selenide/pull/1075">PR 1075</a>.</p>
<h2 id="we-fixed-error-when-starting-microsoft-edge">We fixed error when starting Microsoft Edge</h2>
<p>See <a href="https://github.com/selenide/selenide/issues/1039">issue 1039</a>.<br />
Thanks to <a href="https://github.com/BorisOsipov">Boris Osipov</a> for <a href="https://github.com/selenide/selenide/pull/1084">PR 1084</a>.</p>
<h2 id="news">News</h2>
<ul>
<li>
<p>A funny <a href="https://twitter.com/titusfortner/status/1234862932036608001">dialog</a> in Twitter:
contributor of Selenium and Watir projects Titus Fortner admitted that he watched <a href="/2015/09/23/selenide-on-seleniumconf/">my presentation about Selenide on SeleniumConf</a>,
and even stole some ideas for Watir. And I admitted that some of Selenide ideas were initially stolen from Watir. :)</p>
</li>
<li>A good article <a href="https://phauer.com/2019/modern-best-practices-testing-java/">Modern Best Practices for Testing in Java</a>. A plenty of right ideas.</li>
<li>A post <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 post <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>Some base project <a href="https://github.com/romsper/qa-automation-base/tree/kotlin-junit5-appium">qa-automation-base</a> which has mixed Kotlin + Selenide/Appium + JUnit 5 + Allure + Allure EE + TestRail.
<br /></li>
</ul>
<h2 id="statistics">Statistics</h2>
<p>And for dessert - Selenide download statistics. We are growing!</p>
<center>
<img src="/images/2020/03/selenide.downloads.png" width="800" />
</center>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.8.02020-02-28T00:00:00+00:00https://selenide.org/2020/02/28/selenide-5.8.0
<p>Buenos noches!</p>
<p>We have merged next pack of pull requests and released <a href="https://github.com/selenide/selenide/milestone/90?closed=1">Selenide 5.8.0</a>.</p>
<p>What updates will you see there?</p>
<h2 id="simplified-creation-of-custom-conditions-using-lambdas">Simplified creation of custom conditions using lambdas</h2>
<p>In class <code class="language-plaintext highlighter-rouge">Condition</code> there is a new method <code class="language-plaintext highlighter-rouge">match</code> which allows you to create custom conditions without need to subclass <code class="language-plaintext highlighter-rouge">Condition</code>.
You just need to pass it a lambda.</p>
<p>See examples <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/ConditionsTest.java">in tests</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">-></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>We also added similar methods for collections <code class="language-plaintext highlighter-rouge">anyMatch</code>, <code class="language-plaintext highlighter-rouge">allMatch</code> and <code class="language-plaintext highlighter-rouge">noneMatch</code>.
See examples <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/CollectionMethodsTest.java">in tests</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">-></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">-></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">-></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>See <a href="https://github.com/selenide/selenide/issues/662">issue 662</a>.<br />
Thanks to <a href="https://github.com/dstekanov">Dmytro Stekanov</a> for <a href="https://github.com/selenide/selenide/pull/1059">PR 1059</a>.</p>
<p><br /></p>
<h2 id="added-methods-sibling-and-preceding">Added methods <code class="language-plaintext highlighter-rouge">$.sibling()</code> and <code class="language-plaintext highlighter-rouge">$.preceding()</code></h2>
<p>… which allow you to find “previous” and “following” elements on the same DOM level.
It can be useful when you don’t have good locators, but need to navigate in DOM tree.</p>
<p>See examples <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/SiblingTest.java">in tests</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>See <a href="https://github.com/selenide/selenide/issues/845">issue 845</a>.<br />
Thanks to <a href="https://github.com/dstekanov">Dmytro Stekanov</a> for <a href="https://github.com/selenide/selenide/pull/1064">PR 1064</a>.</p>
<p><br /></p>
<h2 id="added-support-for-pseudo-elements">Added support for pseudo-elements</h2>
<p>As many of you know, there are <em>things</em> in HTML called <em>pseudo-elements</em>: “:before”, “:after”, “:first-letter”, “:first-line”, “:selection”.
They can contains important texts and styles that you sometimes want to check. Now it’s possible.</p>
<p>See examples <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/PseudoTest.java">in tests</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>You can also ask for a value of pseudo-element from <code class="language-plaintext highlighter-rouge">SelenideElement</code> (but we do not welcome this method):</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>See <a href="https://github.com/selenide/selenide/issues/994">issue 994</a>.<br />
Thanks to <a href="https://github.com/Denysss">Denys Shynkarenko</a> for <a href="https://github.com/selenide/selenide/pull/1045">PR 1045</a>.</p>
<p><br /></p>
<h2 id="fixed-softassertionsextension-for-junit5">Fixed SoftAssertionsExtension for JUnit5</h2>
<p>If one of your tests failed, <code class="language-plaintext highlighter-rouge">SoftAssertionsExtension</code> also marked all following tests as failed. Ups.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1071">issue 1071</a>.<br />
Thanks to <a href="https://github.com/vinogradoff">Alexei Vinogradov</a> for <a href="https://github.com/selenide/selenide/commit/e92b250337a36a7225d6fcbdffecbf102f4592da">the fix</a>.</p>
<p><br /></p>
<h2 id="now-click-always-clicks-in-the-center-of-an-element">Now <code class="language-plaintext highlighter-rouge">$.click()</code> always clicks in the CENTER of an element</h2>
<p>Usually method <code class="language-plaintext highlighter-rouge">$.click()</code> did click in the center of the element.
But if you set <code class="language-plaintext highlighter-rouge">Configuration.clickViaJS=true</code>, it clicked in the top left corner.<br />
Not that it was critical, but you never know … Now it always clicks in the center.
Just in case. Just to keep the same behaviour in all cases.</p>
<p>See <a href="https://github.com/selenide/selenide/commit/106c53941c7188c5a19677ad45fbdea910960c73">commit 106c53941c718</a>.</p>
<p><br /></p>
<h2 id="news">News</h2>
<ul>
<li>Wow! John C. Pratt created a <a href="https://chrome.google.com/webstore/detail/selenide-exporter-for-kat/mkbfcgpbkcaieiajhllpdocjfnfcbmlm">Selenide Exporter for Katalon Recorder</a>
(works with <a href="https://chrome.google.com/webstore/detail/katalon-recorder-selenium/ljdobmomdgdljniojadhoplhkpialdid">Katalon Recorder</a>).</li>
<li>We discovered <a href="https://github.com/razielsd/phpSelenide">phpSelenide</a> - a Selenide port to PHP.</li>
<li>And if you didn’t know, <a href="https://github.com/automician/selenejs">SeleneJS</a> - a Selenide port to JavaScript.</li>
</ul>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.7.02020-02-07T00:00:00+00:00https://selenide.org/2020/02/07/selenide-5.7.0
<p>Buchahos!</p>
<p>Recently we got a lot of pull requests with lot of useful changes. This is the power of open source!</p>
<p>We have merged all those changes and released <a href="https://github.com/selenide/selenide/milestone/89?closed=1">Selenide 5.7.0</a>.</p>
<h2 id="added-setting-configurationdownloadsfolder">Added setting <code class="language-plaintext highlighter-rouge">Configuration.downloadsFolder</code></h2>
<p>Before now, Selenide downloaded files to folder <code class="language-plaintext highlighter-rouge">build/reports</code> - the same folder which contains generated test reports. <br />
But sometimes people want to have reports and screenshots in separate folders.<br />
For those people we added a dedicated setting <code class="language-plaintext highlighter-rouge">Configuration.downloadsFolder</code> - now Selenide will download files there.</p>
<p>By default it’s <code class="language-plaintext highlighter-rouge">build/downloads</code>.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1025">issue 1025</a>.<br />
Thanks to <a href="https://github.com/dstekanov">Dmytro Stekanov</a> for <a href="https://github.com/selenide/selenide/pull/1041">PR 1041</a>.</p>
<p><br /></p>
<h3 id="download-files-to-configurationdownloadsfolder-instead-of-downloads">Download files to <code class="language-plaintext highlighter-rouge">Configuration.downloadsFolder</code> instead of <code class="language-plaintext highlighter-rouge">~/Downloads</code></h3>
<p>We had one more nuance when downloading files via proxy (<code class="language-plaintext highlighter-rouge">Configuration.fileDownload=PROXY</code>). <br />
Selenide downloads files to its own folder <code class="language-plaintext highlighter-rouge">build/reports</code> (now <code class="language-plaintext highlighter-rouge">build/downloads</code>), but browser also downloads the same
files to folder <code class="language-plaintext highlighter-rouge">~/Downloads</code> (or what is the system default). It takes disk space, and nobody cleans up those files after test run.</p>
<p>Now Selenide configures webdriver to download files to folder <code class="language-plaintext highlighter-rouge">build/downloads</code>.</p>
<ol>
<li>But only for Chrome and Firefox by now.</li>
<li>And only in case of Selenide opens webdriver by itself.</li>
</ol>
<p>See <a href="https://github.com/selenide/selenide/issues/1057">issue 1057</a>.
Thanks to <a href="https://github.com/dkorobtsov">Dmitri Korobtsov</a> for code review of <a href="https://github.com/selenide/selenide/pull/1058">PR 1058</a>.</p>
<p><br /></p>
<h3 id="added-method-for-switching-between-windows-with-custom-timeout">Added method for switching between windows with custom timeout</h3>
<p>As you know, Selenide has methods for switching between tabs/windows:</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>This method is smart enough to wait until window is loaded. But it was impossible to set a timeout: the default 4 seconds was used here.</p>
<p>Now we added a overloaded method with timeout parameter:</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>See <a href="https://github.com/selenide/selenide/issues/399">issue 399</a>.<br />
Thanks to <a href="https://github.com/dstekanov">Dmytro Stekanov</a> for <a href="https://github.com/selenide/selenide/pull/1054">PR 1054</a>.</p>
<p><br /></p>
<h3 id="added-logging-of-readonly-attribute">Added logging of “readonly” attribute</h3>
<p>See <a href="https://github.com/selenide/selenide/issues/990">issue 990</a>.<br />
Thanks to <a href="https://github.com/dstekanov">Dmytro Stekanov</a> for <a href="https://github.com/selenide/selenide/pull/1042">PR 1042</a>.</p>
<p><br /></p>
<h3 id="fixed-indexoutofboundsexception">Fixed IndexOutOfBoundsException</h3>
<p>… when searching first/last element of an empty collection</p>
<p>See <a href="https://github.com/selenide/selenide/issues/991">issue 991</a>.<br />
Thanks to <a href="https://github.com/dstekanov">Dmytro Stekanov</a> for <a href="https://github.com/selenide/selenide/pull/1043">PR 1043</a>.</p>
<p><br /></p>
<h3 id="and-several-screenshot-improvements">And several screenshot improvements</h3>
<h4 id="1-returned-the-lost-screenshots-in-screenshotsgetlastscreenshot">1. Returned the lost screenshots in <code class="language-plaintext highlighter-rouge">Screenshots.getLastScreenshot()</code></h4>
<p>See <a href="https://github.com/selenide/selenide/issues/814">issue 814</a> and <a href="https://github.com/selenide/selenide/issues/880">issue 880</a>. <br />
Thanks to <a href="https://github.com/petroOv-PDFfiller">Petro Ovcharenko</a> for <a href="https://github.com/selenide/selenide/pull/1052">PR 1052</a>.</p>
<p><br /></p>
<h4 id="2-fixed-link-to-screenshots-in-jenkins">2. Fixed link to screenshots in Jenkins</h4>
<p>Now Selenide can read environment variable <code class="language-plaintext highlighter-rouge">BUILD_URL</code>, and you don’t need to set system variable <code class="language-plaintext highlighter-rouge">BUILD_URL</code> in your build scripts.</p>
<p>Thanks to <a href="https://github.com/GongYi">GongYi</a> for <a href="https://github.com/selenide/selenide/pull/1049">PR 1049</a>.</p>
<p><br /></p>
<h4 id="3-fixed-paths-to-screenshots-in-multi-module-maven-builds">3. Fixed paths to screenshots in multi-module Maven builds</h4>
<p>Thanks to <a href="https://github.com/GongYi">GongYi</a> for <a href="https://github.com/selenide/selenide/pull/1049">PR 1049</a>.</p>
<p><br /></p>
<h3 id="upgraded-to-webdrivermanager-381">Upgraded to WebDriverManager 3.8.1</h3>
<p>See <a href="https://github.com/bonigarcia/webdrivermanager/compare/webdrivermanager-3.8.1...master">changelog</a> (including support for Edge 80).</p>
<p><br />
<br /></p>
<h1 id="events">Events</h1>
<h3 id="seleniumcamp-2020">SeleniumCamp 2020</h3>
<p>Welcome to Kiev in February, 21-22 to <a href="https://seleniumcamp.com/program/">SeleniumCamp</a> conference! <br />
I will present two talks:</p>
<ul>
<li><a href="https://seleniumcamp.com/talk/flaky-tests-method/">Flaky tests: The Method</a></li>
<li><a href="https://seleniumcamp.com/talk/selenide-for-web-android-and-ios/">Threesome: Selenide for Web, Android and iOS</a></li>
</ul>
<p>and I will also hold an informal BOF session about <a href="https://seleniumcamp.com/talk/bof-glorious-past-and-promising-future-of-selenide/">Selenide roadmap</a>.</p>
<h3 id="meetup-about-selenide-in-germany">Meetup about Selenide in Germany</h3>
<p>Some folks organize a <a href="https://stugrm.de/stugrm-meetups/">Selenide meetup</a> in Germany in February, 12.<br />
That’s cool, right?</p>
<p><br /></p>
<h3 id="downloads-statistics">Downloads statistics</h3>
<p>The number of Selenide downloads over the year increased 2.5 times from 40 thousand to 110 thousand.</p>
<center>
<img src="/images/2020/02/selenide.downloads.png" width="800" />
</center>
<p><br /></p>
<p>And the number of unique IPs exceeded 20 thousand:</p>
<center>
<img src="/images/2020/02/selenide.unique-ips.png" width="800" />
</center>
<p><br /></p>
<p>We are growing!</p>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.6.12020-01-14T00:00:00+00:00https://selenide.org/2020/01/14/selenide-5.6.1
<p>Happy New Year for everyone!</p>
<p>New year - new release. Please welcome <a href="https://github.com/selenide/selenide/milestone/88?closed=1">Selenide 5.6.1</a>.</p>
<h1 id="added-method-selenideexecuteasyncscript">Added method <code class="language-plaintext highlighter-rouge">Selenide.executeAsyncScript()</code></h1>
<p>I guess all of you have used method <code class="language-plaintext highlighter-rouge">Selenide.executeJavaScript()</code>.
JavaScript gives us <a href="/2019/12/24/advent-calendar-javascript-tricks/">a big power</a> in test automation.</p>
<p>Now we added a method <code class="language-plaintext highlighter-rouge">Selenide.executeAsyncScript()</code>. It can be used for executing asynchronous functions (like <code class="language-plaintext highlighter-rouge">setTimeout</code>, <code class="language-plaintext highlighter-rouge">$.get</code> etc.)</p>
<p>Please note that it’s a little bit harder to use than <code class="language-plaintext highlighter-rouge">executeJavaScript()</code>.<br />
After calling asynchronous JS methods need to execute <code class="language-plaintext highlighter-rouge">callback</code> with a return value. You have to get <code class="language-plaintext highlighter-rouge">callback</code> from a <em>last argument</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">" // Here is your asynchronous JS code: "</span> <span class="o">+</span>
<span class="s">" ... "</span> <span class="o">+</span>
<span class="s">" // and return to Selenium: "</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>See <a href="https://github.com/selenide/selenide/issues/1030">issue 1030</a>.<br />
Thanks to <a href="https://github.com/tyge68">Thierry Ygé</a> for <a href="https://github.com/selenide/selenide/pull/1031">PR 1031</a>.</p>
<p><br /></p>
<h1 id="now-selenide-can-download-files-without-content-disposition-header-via-proxy">Now Selenide can download files without <code class="language-plaintext highlighter-rouge">Content-Disposition</code> header (via proxy)</h1>
<p>As you know, Selenide can download files via its built-in proxy server.<br />
But until now, it intercepted only server responses containing <code class="language-plaintext highlighter-rouge">Content-Disposition</code> header (to get the name of file being downloaded).</p>
<p>But it appeared that this header is not always required. Sometimes files can be downloaded without this header.</p>
<p>Now Selenide proxy got to be smarter. Starting from Selenide 5.6.1, it works as follows:</p>
<ol>
<li>Before starting download, it waits until all previous requests/responses between browser and server are completed.</li>
<li>It clicks the download button.</li>
<li>It intercepts ALL requests between browser and server (no matter which headers they contain).</li>
<li>And tries to understand which of them is more like a file download.</li>
</ol>
<p>If this response doesn’t contain <code class="language-plaintext highlighter-rouge">Content-Disposition</code> header, the name of the file is taken from URL.</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1034">issue 1034</a> and <a href="https://github.com/selenide/selenide/pull/1035">PR 1035</a>.</p>
<p><br /></p>
<h1 id="fix-method-webdriverrunnerusing">Fix method <code class="language-plaintext highlighter-rouge">WebDriverRunner.using()</code></h1>
<p>We <a href="/2019/10/16/selenide-5.4.0/#add-method-using">added method <code class="language-plaintext highlighter-rouge">using</code></a> in October, 2019.<br />
We recently found a bug in this method: it closed the webdriver (but should not). Now we fixed this bug.</p>
<p>See <a href="https://github.com/selenide/selenide/commit/4d1b19972d">commit 4d1b19972d</a>.</p>
<p><br /></p>
<h1 id="upgraded-to-webdrivermanager-380">Upgraded to WebDriverManager 3.8.0</h1>
<p>It contains lot of bugfixes, including those reported by me :)</p>
<p>See <a href="https://github.com/bonigarcia/webdrivermanager/compare/webdrivermanager-3.8.0...master">changelog</a>. <br />
Among other improvements, WDM can now work without internet access.</p>
<p><br /></p>
<h2 id="news">News</h2>
<ul>
<li>Wow! Welcome <a href="https://vitalyzinevich.visualstudio.com/_git/Selenious">Selenious</a> - a port of Selenide to .NET platform.</li>
<li>Article from 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>My video from Cyprus Quality Conference <a href="https://youtu.be/Y04rU7qV7Vg">Threesome: Selenide for Web, Android and iOS</a> in October, 2019.</li>
<li>In case you missed it: series of posts <a href="/blog">Selenide Advent Calendar 2019</a></li>
</ul>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Released Selenide 5.6.02019-12-26T00:00:00+00:00https://selenide.org/2019/12/26/selenide-5.6.0
<p>Good morning!</p>
<p>In the end of the year, we released <a href="https://github.com/selenide/selenide/milestone/87?closed=1">Selenide 5.6.0</a> with one significant change.</p>
<p>We replaced (outdated) <code class="language-plaintext highlighter-rouge">BrowserMobProxy</code> by its fork <code class="language-plaintext highlighter-rouge">BrowserUpProxy</code> (current version 2.0.1).</p>
<p>See <a href="https://github.com/selenide/selenide/issues/1019">issue 1019</a>.<br />
Thanks to <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/1020">PR 1020</a>.</p>
<h2 id="what-good-is-there-is-browserupproxy">What good is there is <code class="language-plaintext highlighter-rouge">BrowserUpProxy</code>?</h2>
<p>It</p>
<ul>
<li>supports Brotli Compression (in addition to gzip)</li>
<li>supports HTTP/2</li>
<li>based on actively maintained fork <a href="https://github.com/mrog/LittleProxy">LittleProxy</a></li>
<li>uses a better <a href="https://github.com/sdstoehr/har-reader">HAR reader</a></li>
<li>can filter HAR entries</li>
<li>supports versioned headers for JSON like <code class="language-plaintext highlighter-rouge">Content-Type=application/something-v1+json</code></li>
<li>has built-in asserts for network and pages</li>
</ul>
<p>Here is the <a href="https://github.com/browserup/browserup-proxy/blob/master/CHANGELOG.md">full changelog</a> of <code class="language-plaintext highlighter-rouge">BrowserUpProxy</code> (compared to BrowserMobProxy).</p>
<h2 id="how-to-upgrade">How to upgrade?</h2>
<p>In most cases, you don’t need to change anything. Everything just work as before.<br />
Some changes are required only in 2 cases:</p>
<h4 id="1-if-you-declared-bmp-dependency-explicitly-you-need-to-replace">1. If you declared BMP dependency explicitly, you need to replace</h4>
<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>by</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>
<h4 id="2-if-you-implemented-requestfilter-or-responsefilter">2. If you implemented <code class="language-plaintext highlighter-rouge">RequestFilter</code> or <code class="language-plaintext highlighter-rouge">ResponseFilter</code>,</h4>
<p>you need to replace import</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>by</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>That’s it. Nothing more.</p>
<p><br /></p>
<h2 id="news">News</h2>
<ul>
<li>Google post about <a href="https://testing.googleblog.com/2019/12/testing-on-toilet-tests-too-dry-make.html">DAMP and DRY principles</a></li>
<li>One more framework on top of Selenide: <a href="https://www.justtestlah.qa/">JustTestLah! (JTL)</a> - Hybrid of BDD, Selenide, Appium for Android, iOS and Web</li>
<li>In case if you missed it, posts series <a href="/blog">Selenide Advent Calendar</a></li>
</ul>
<p><br /></p>
<p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
JavaScript tricks2019-12-24T00:00:00+00:00https://selenide.org/2019/12/24/advent-calendar-javascript-tricks
<p>Good Christmas!</p>
<p>Today is December, 24. It’s Christmas. It’s the last day of our Selenide Advent Calendar.</p>
<p>In this last day, we will play JavaScript.</p>
<p>As a language, JavaScript is a disaster, but it gives a big power when used in automated tests.<br />
It allows you doing things that are impossible with pure WebDriver.</p>
<p>Let me show few examples from real projects.</p>
<h2 id="pick-a-date">Pick a date</h2>
<p>There is a lot of different “date pickers” out there. It’s always a headache to pick a date using them.</p>
<p>How to pick a date in your test?</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>A straightforward way could be like this:</p>
<ol>
<li>Click a “calendar” icon</li>
<li>Click a year number</li>
<li>Click “previous month” arrow (how many times?)</li>
<li>Click a day</li>
<li>Ooops, today is February, 29. The test failed.</li>
</ol>
<p>This way is <strong>slow and unstable</strong>.</p>
<p><br /></p>
<h4 id="and-this-is-how-it-can-be-implemented-using-javascript">And this is how it can be implemented using JavaScript:</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>It’s <strong>fast and stable</strong>.</p>
<p>You might be confused because it’s not the “real” way. We will discuss it in the end. Hold on.</p>
<h2 id="hide-the-calendar">Hide the calendar</h2>
<p>Assuming that the calendar was opened, how to close it?</p>
<p>A straightforward solution would be to click the “cross” in the corner of calendar modal dialog. Again, it’s slow and unstable:</p>
<ul>
<li>the “cross” is always located in different corners</li>
<li>location of the “cross” can change depending on design, browser size etc.</li>
<li>sometimes calendar popup is opened slowly - you need to add explicit wait for the “cross” to immediately close it.</li>
</ul>
<p>The idiotic situation.</p>
<p><br /></p>
<h4 id="it-can-be-done-much-easier-with-javascript">It can be done much easier with JavaScript:</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>It’s <strong>fast and stable</strong>.</p>
<h2 id="flip-a-flipper">Flip a flipper</h2>
<p>Imagine a page with “flipper” for choosing a card. To select a card, user has to make a right finger movement in a right direction.<br />
<em>How to emulate it with Selenium?</em>
It’s possible. All those Drag’n’Drop, Actions. Press, hold, move, release. All this is <strong>slow and unstable</strong>.<br />
It can easily be broken because of minor design changes, different browser size, focus lost etc.</p>
<h4 id="and-this-a-solution-with-javascript">And this a solution with JavaScript:</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>Yes, it’s not trivial. We had to dive into the flipper’s code and understand what JS code it calls on flipping.<br />
And call similar JS code from test. Yes, you need to apply your head, but this solution is <strong>fast and stable.</strong></p>
<h2 id="choose-and-option-in-bootstrap-select">Choose and option in bootstrap select</h2>
<p>Many UI frameworks replace the standard <code class="language-plaintext highlighter-rouge"><select></code> with custom home-made “nice”/”usable” elements, made from
bunch of <code class="language-plaintext highlighter-rouge"><div></code>s, <code class="language-plaintext highlighter-rouge"><span></code>s, <code class="language-plaintext highlighter-rouge"><li></code>s etc. with bunch of CSS classes and styles. It’s always a pain for automation.</p>
<p>One of such UI frameworks is Bootstrap. It also has its <code class="language-plaintext highlighter-rouge"><select></code>. We tried hard, but failed to clicks all those
<code class="language-plaintext highlighter-rouge"><div></code>s and <code class="language-plaintext highlighter-rouge"><span></code>s in the right order to select the right option.</p>
<p>At the end, we implement the method:</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>with 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>Fast and stable.</strong></p>
<p>By the way, with the help of <a href="https://selenide.org/2019/09/02/selenide-5.3.0/"><code class="language-plaintext highlighter-rouge">execute</code> method</a> you can make it even nicer:</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="slider">Slider</h2>
<p>There is a slider on a page. User can drag the slider back and forth from 0 to 100.<br />
How to do it in test?</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>Even classical Drag’n’Drop doesn’t work here because we just haven’t a target element.<br />
Again, we can use Actions: press - hold - drag (by coordinates?) - release. Again, it’s <strong>slow and unstable</strong>.</p>
<h4 id="but-we-can-use-javascript">But we can use JavaScript:</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>Again, we had to dive into the slider code. But it works. It’s <strong>fast and stable</strong>.</p>
<h2 id="but-its-not-real">But it’s not real?</h2>
<p>I know, many of you are frustrated because “it’s not real, it’s fake. Tests must emulate real user’s behaviour.
Otherwise tests can miss some real problem.”</p>
<p>I understand.</p>
<p>But I will argue.</p>
<blockquote>
<p>Fast and stable tests
are much, much better than
“realistic” (but slow and unstable) tests.</p>
</blockquote>
<ul>
<li>If 30% of your tests fail during every run,</li>
<li>If you spent few hours to analyze every failed build,</li>
<li>If you manually click through your “automated” scripts to check that functionality is not broken (and it was just a flaky test),</li>
<li>If you fill an excel with failed-but-manually-checked test,</li>
<li>If there is <em>no trust for tests</em> in your company,</li>
</ul>
<p>then <em>what the hell is the benefit of your tests</em>?<br />
Hard, only harm.</p>
<ul>
<li>I prefer fast and stable tests.</li>
<li>I prefer tests that can easily emulate dependencies and check “complex” scenarios that are almost impossible to reproduce in a “realistic” way.</li>
<li>I prefer to live in peace with understanding that the goal of automated testing was never to <em>automate everything</em>.</li>
</ul>
<p><br /></p>
<p>You might still say:</p>
<h3 id="nevertheless-my-soul-is-calmer-when-everything-is-for-real">Nevertheless, my soul is calmer when everything is “for real”.</h3>
<p>Sorry, I have to upset you.</p>
<ul>
<li>You “realistic” Selenium WebDriver tests will never be <em>real</em>. They work <em>differently</em> (compare to real users).
WebDriver sends a http request for each your command, and even - surprise! - applies some logic on JavaScript to check visibility of elements etc.</li>
<li>In some sense, actions with JavaScript are even more “realistic” that with WebDriver. It’s closer to what browser actually does.</li>
<li>And even your manual testers clicking through you scenarios - are <em>not real</em>! They work <em>differently</em> (compare to real users).</li>
</ul>
<p>Live now with it. :)</p>
<h2 id="whats-next">What’s next?</h2>
<p>That’s it. It was the last post of Selenide Advent Calendar 2019. Uhhhh!</p>
<p>I will be honest: I wrote it to train my hands and get used to write a lot. I hope it will help me to <a href="https://selenide.org/selenide-site-ng/">update our site</a>
and write Selenide documentation. Maybe even book. :)</p>
<p>These are the plans for next year.</p>
<p>Happy New Year!</p>
<p><br />
<a href="http://asolntsev.github.io/">Andrei Solntsev</a></p>
<p>selenide.org</p>
Defaŭlta lingvo2019-12-22T00:00:00+00:00https://selenide.org/2019/12/22/advent-calendar-defaulta-lingvo
<h1 id="defaŭlta-lingvo">Defaŭlta lingvo</h1>
<p>The name of today’s topic is Esperanto and translates as “default language”.</p>
<p>You may have noticed that some web applications or sites change their language depending on either your browser language setting or on your location.</p>
<h2 id="problem">Problem</h2>
<p>In case you have international developers in your team all writing and running some tests on different computer, you also may have noticed that the very same tests is failing or passing because the applications was displayed in different languages on different machines.</p>
<p>If the application decides about the language based on user location, it can be difficult to write stable tests running everywhere. But if it is just “preferred browser language of the user”, then your task is much easier.</p>
<h2 id="solution">Solution</h2>
<p>So if you have a test which is supposed to run with language that differs from the default language of your browser, you have following options. Let’s imagine you are writing the tests for <em>German</em> Locale.</p>
<ul>
<li>Change the default language of you operational system. Poor you. Now the most of the programs will be showing in German. <em><strong>Ordnung muss sein!</strong></em></li>
<li>Take your browser and setup it to be German the preferable language. Save away the profile. Google and experiment a lot about loading custom browser profile before starting your tests. Don’t forget to remove German from the top of preferred languages or otherwise, you know already, <em><strong>Ordnung….</strong></em></li>
<li>Just make use of Chrome preference “intl.accept_languages” and set it to “de” (for German).</li>
</ul>
<p>Of course you can very easily do it in Selenide.
Setup the system variable <code class="language-plaintext highlighter-rouge">chromeoptions.prefs=intl.accept_languages=de</code></p>
<p>You can do it either in 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>or even better in configuration file of Maven or 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"><plugin></span>
<span class="nt"><artifactId></span>maven-surefire-plugin<span class="nt"></artifactId></span>
<span class="nt"><version></span>2.xx.yy<span class="nt"></version></span>
<span class="nt"><configuration></span>
<span class="nt"><systemPropertyVariables></span>
...
<span class="nt"><chromeoptions.prefs></span>intl.accept_languages=de<span class="nt"></chromeoptions.prefs></span>
<span class="nt"></systemPropertyVariables></span>
<span class="nt"></configuration></span>
<span class="nt"></plugin></span>
...
</code></pre></div></div>
<h3 id="gradle">Gradle</h3>
<p>likewise for gradle in <code class="language-plaintext highlighter-rouge">gradle.properties</code> (you additionally need a line or two in <code class="language-plaintext highlighter-rouge">build.gradle</code> to get this parameter transferred in to the test task in gradle)</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="command-line">Command-line</h3>
<p>You can then override the setting running <code class="language-plaintext highlighter-rouge">mvn test</code> or <code class="language-plaintext highlighter-rouge">gradle test</code> defining another value in the command line <code class="language-plaintext highlighter-rouge">-Dchromeoptions.prefs=intl.accept_languages=ru</code></p>
<h2 id="example">Example</h2>
<p>Just run this short test and see the effect of different language settings.</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>I wish you all <em><strong>Fröhliche Weihnachten</strong></em> and <em><strong>Guten Rutsch</strong></em>!</p>
<p><strong>Alexei Vinogradov</strong></p>
Big “wait” theory2019-12-20T00:00:00+00:00https://selenide.org/2019/12/20/advent-calendar-big-wait-theory
<h1 id="big-wait-theory">Big “wait” theory</h1>
<p>The topic of “wait” mechanism is well-known and sometimes can be controversial.<br />
The fact is that modern websites are problematic to be tested by test automation frameworks and generate many situations
where standard Selenium methods are ineffective. If you have read Selenide documentation, you already know that classic explicit waits like:</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"><</span><span class="n">timeOutForElement</span><span class="o">>))</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">(<</span><span class="n">cssSelector</span><span class="o">>)));</span>
</code></pre></div></div>
<p>or</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"><</span><span class="n">timeOutForElement</span><span class="o">>))</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">(<</span><span class="n">cssSelector</span><span class="o">>)));</span>
</code></pre></div></div>
<p>have been replaced by Selenide with (way shorter) variants:</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">(<</span><span class="n">cssSelector</span><span class="o">>).</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">(<</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><strong>As we know assertions in Selenide are new version of explicit wait, which is well-described for example in <a href="https://selenide.org/documentation.html">documentation</a>.</strong></p>
<p>Today we won’t be looking at assertions and wait mechanism from the technical point of view, but we will think about good ideas and examples of using particular assertions in different situations.</p>
<h2 id="modern-problems-require-modern-solutions">Modern problems require modern solutions</h2>
<h3 id="1-threadsleep">1. <code class="language-plaintext highlighter-rouge">Thread.sleep()</code></h3>
<p>This is the worst possible thing, that could happen to our tests in Selenium.</p>
<p>Some situations just required to use it, and there were no other solutions to move forward.
Sometimes QAs try to use it to wait for some page to load, sometimes they try to wait for some element when other
waits fail. Unfortunately, this way we can lose a lot of time.
If we use it only in one test, it’s not that dangerous cause it will take probably around 4 seconds of our time.
But if we use it in 150 tests, it will substantially increase the time of performance.
There is no need to explain why it’s a bad thing.
Although <code class="language-plaintext highlighter-rouge">sleep()</code> is still available in Selenide, smart assertions mentioned before make it useless in sense of
waiting for anything on the page. Check next points.</p>
<h3 id="2-how-to-wait-for-page-to-load">2. How to wait for page to load?</h3>
<p>The easiest way is to choose some element from the page that we want to load and use Selenide method:</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>Notice that Selenide will try to find the element first, and then it will wait for the element to be visible.
If it has not found the element it means that the page hasn’t loaded.</p>
<p>Also, we can designate some element from the page that we are leaving and use method:</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>This way we create double-check for moving from one page to another, even if it takes a lot of time and previously we needed <code class="language-plaintext highlighter-rouge">Thread.sleep()</code>.</p>
<h3 id="3-changing-state-of-an-element">3. Changing state of an element</h3>
<p>It happens that we want to validate the state of an element that changes depending
on actions taken by user. For example, element contains text informing us if some file has been uploaded or not.
It is possible that we will upload the file but it will take some time to change the state of element, because
back-end has to process the task and give back the information.</p>
<p>Normally in our test we would li