Selenide Selenide - Andrei Solntsev https://selenide.org/rss https://selenide.org 2024-11-11T20:07:43+00:00 2024-11-11T20:07:43+00:00 1800 Released 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&amp;list=PL9Z-JgiTsOYRfoG_mcRBlTUIFPIknhQ6S&amp;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">&lt;select&gt;</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&amp;list=PL9Z-JgiTsOYRJCXuEOGXLH1w1oImoprnq&amp;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 &amp; Web</a> from Testμ 2024 conference (LambdaTest)</li> <li>My video <a href="https://www.youtube.com/watch?v=-TvVCxmb9ss&amp;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&amp;ab_channel=JoseDiaz">about Selenide in Spanish</a> by Jose Diaz</li> <li>Video <a href="https://www.youtube.com/watch?v=zDw0iGdSghY&amp;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> https://selenide.org/2024/09/15/selenide-7.5.0/ https://selenide.org/2024/09/15/selenide-7.5.0 2024-09-15T00:00:00+00:00 Released 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">-&gt;</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">-&gt;</span> <span class="k">new</span> <span class="nc">HttpResponse</span><span class="o">()</span> <span class="o">.</span><span class="na">setStatus</span><span class="o">(</span><span class="mi">429</span><span class="o">)</span> <span class="o">.</span><span class="na">addHeader</span><span class="o">(</span><span class="s">"Content-Type"</span><span class="o">,</span> <span class="s">"application/json"</span><span class="o">)</span> <span class="o">.</span><span class="na">setContent</span><span class="o">(</span><span class="n">utf8String</span><span class="o">(</span><span class="s">"{votes: 2133326, for: 99.23, against: 0.77}"</span><span class="o">))</span> <span class="o">);</span> </code></pre></div></div> <p>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">&lt;</span><span class="nc">XCUIElementTypeButton</span> <span class="o">...</span> <span class="n">visible</span><span class="o">=</span><span class="s">"false"</span><span class="o">&gt;...</span> <span class="nc">Caused</span> <span class="nl">by:</span> <span class="nl">UnsupportedCommandException:</span> <span class="nc">Unhandled</span> <span class="nl">endpoint:</span> <span class="o">/</span><span class="n">session</span><span class="o">/</span><span class="mi">28</span><span class="o">...</span><span class="mi">13</span><span class="o">/</span><span class="n">element</span><span class="o">/</span><span class="mo">07000000</span><span class="o">-</span><span class="mo">0000</span><span class="o">-</span><span class="mo">0000</span><span class="o">-</span><span class="no">CF35</span><span class="o">-</span><span class="mo">000000000000</span><span class="o">/</span><span class="n">css</span><span class="o">/</span><span class="n">opacity</span> <span class="o">...</span> </code></pre></div></div> <p>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">&amp;</span><span class="n">u</span><span class="o">=</span><span class="n">https</span><span class="o">%</span><span class="mi">3</span><span class="no">A</span><span class="c1">//zopa/</span> <span class="nc">Build</span> <span class="nl">info:</span> <span class="nl">version:</span> <span class="err">'</span><span class="mf">4.20</span><span class="o">.</span><span class="mi">0</span><span class="err">'</span><span class="o">,</span> <span class="nl">revision:</span> <span class="err">'</span><span class="mi">866</span><span class="n">c76ca80</span><span class="err">'</span> </code></pre></div></div> <p>P.S. 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> https://selenide.org/2024/04/28/selenide-7.3.1/ https://selenide.org/2024/04/28/selenide-7.3.1 2024-04-28T00:00:00+00:00 Released 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&lt;WebElement&gt;)</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">&lt;</span><span class="n">a</span> <span class="n">id</span><span class="o">=</span><span class="s">"generate-report"</span><span class="o">&gt;</span> </code></pre></div></div> <p>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">&lt;</span><span class="n">a</span> <span class="n">id</span><span class="o">=</span><span class="s">"generate-report"</span><span class="o">&gt;,</span> <span class="n">so</span> <span class="n">method</span> <span class="no">HTTPGET</span> <span class="n">cannot</span> <span class="n">download</span> <span class="n">the</span> <span class="n">file</span><span class="o">.</span> <span class="nc">Please</span> <span class="k">try</span> <span class="n">another</span> <span class="n">download</span> <span class="nl">method:</span> <span class="no">FOLDER</span><span class="o">,</span> <span class="no">CDP</span> <span class="n">or</span> <span class="no">PROXY</span><span class="o">.</span> <span class="nc">Read</span> <span class="n">more</span> <span class="n">about</span> <span class="n">possible</span> <span class="n">download</span> <span class="nl">methods:</span> <span class="nl">https:</span><span class="c1">//selenide.org/javadoc/current/com/codeborne/selenide/FileDownloadMode.html</span> </code></pre></div></div> <p>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> https://selenide.org/2024/02/27/selenide-7.2.0/ https://selenide.org/2024/02/27/selenide-7.2.0 2024-02-27T00:00:00+00:00 Released 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&amp;ab_channel=Jfokus&amp;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> https://selenide.org/2024/02/07/selenide-7.1.0/ https://selenide.org/2024/02/07/selenide-7.1.0 2024-02-07T00:00:00+00:00 Released 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> https://selenide.org/2023/10/26/selenide-7.0.1/ https://selenide.org/2023/10/26/selenide-7.0.1 2023-10-26T00:00:00+00:00 Released 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 &amp; 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> https://selenide.org/2023/10/25/selenide-7.0.0/ https://selenide.org/2023/10/25/selenide-7.0.0 2023-10-25T00:00:00+00:00 Released 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> https://selenide.org/2023/10/18/selenide-6.19.1/ https://selenide.org/2023/10/18/selenide-6.19.1 2023-10-18T00:00:00+00:00 Released 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">&lt;div</span> <span class="na">id=</span><span class="s">"status"</span><span class="nt">&gt;</span> <span class="nt">&lt;span&gt;</span> Fighting spirit <span class="nt">&lt;/span&gt;</span> <span class="nt">&lt;span&gt;</span> seething<span class="ni">&amp;nbsp;</span>\u200Breality <span class="nt">&lt;/span&gt;</span> <span class="nt">&lt;/div&gt;</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&amp;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 &amp; 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> https://selenide.org/2023/09/28/selenide-6.19.0/ https://selenide.org/2023/09/28/selenide-6.19.0 2023-09-28T00:00:00+00:00 Released 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">&lt;select&gt;</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> https://selenide.org/2023/09/06/selenide-6.18.0/ https://selenide.org/2023/09/06/selenide-6.18.0 2023-09-06T00:00:00+00:00 Released 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> https://selenide.org/2023/08/24/selenide-6.17.2/ https://selenide.org/2023/08/24/selenide-6.17.2 2023-08-24T00:00:00+00:00 Released 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> https://selenide.org/2023/08/20/selenide-6.17.1/ https://selenide.org/2023/08/20/selenide-6.17.1 2023-08-20T00:00:00+00:00 Released 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> https://selenide.org/2023/08/02/selenide-6.17.0/ https://selenide.org/2023/08/02/selenide-6.17.0 2023-08-02T00:00:00+00:00 Released 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">&lt;tspan&gt;</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">&lt;tspan&gt;</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">&lt;svg&gt;</span> <span class="nt">&lt;text</span> <span class="na">x=</span><span class="s">"10"</span> <span class="na">y=</span><span class="s">"30"</span> <span class="na">class=</span><span class="s">"small"</span><span class="nt">&gt;</span> People want to see <span class="nt">&lt;tspan&gt;</span>gratitude<span class="nt">&lt;/tspan&gt;</span>. <span class="nt">&lt;/text&gt;</span> <span class="nt">&lt;text</span> <span class="na">x=</span><span class="s">"10"</span> <span class="na">y=</span><span class="s">"60"</span> <span class="na">class=</span><span class="s">"small"</span><span class="nt">&gt;</span> We are not <span class="nt">&lt;tspan&gt;</span>Amazon<span class="nt">&lt;/tspan&gt;</span> warehouse. <span class="nt">&lt;/text&gt;</span> <span class="nt">&lt;text</span> <span class="na">x=</span><span class="s">"10"</span> <span class="na">y=</span><span class="s">"90"</span> <span class="na">class=</span><span class="s">"small"</span><span class="nt">&gt;</span> Thank you, <span class="nt">&lt;tspan&gt;</span>Ben Wallace<span class="nt">&lt;/tspan&gt;</span>! <span class="nt">&lt;/text&gt;</span> <span class="nt">&lt;/svg&gt;</span> </code></pre></div></div> <p>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> https://selenide.org/2023/07/24/selenide-6.16.1/ https://selenide.org/2023/07/24/selenide-6.16.1 2023-07-24T00:00:00+00:00 Released 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">&lt;option&gt;</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 &lt;input type="date"&gt;</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 &lt;input type="datetime-local"&gt;</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 &lt;input type="time"&gt;</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&amp;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> https://selenide.org/2023/07/02/selenide-6.16.0/ https://selenide.org/2023/07/02/selenide-6.16.0 2023-07-02T00:00:00+00:00 Released 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">&lt;</span><span class="nc">WebElement</span><span class="o">&gt;</span> <span class="n">webElements</span><span class="o">)</span> <span class="o">{</span> <span class="k">return</span> <span class="n">webElements</span><span class="o">.</span><span class="na">stream</span><span class="o">()</span> <span class="o">.</span><span class="na">map</span><span class="o">(</span><span class="n">webElement</span> <span class="o">-&gt;</span> <span class="n">webElement</span><span class="o">.</span><span class="na">getText</span><span class="o">().</span><span class="na">startsWith</span><span class="o">(</span><span class="s">"Z"</span><span class="o">))</span> <span class="o">.</span><span class="na">reduce</span><span class="o">(</span><span class="kc">true</span><span class="o">,</span> <span class="o">(</span><span class="n">x</span><span class="o">,</span> <span class="n">y</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="n">x</span> <span class="o">&amp;&amp;</span> <span class="n">y</span><span class="o">);</span> <span class="o">}</span> <span class="o">}</span> <span class="err">$$</span><span class="o">(</span><span class="s">".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">&lt;</span><span class="nc">WebElement</span><span class="o">&gt;</span> <span class="n">elements</span> <span class="o">=</span> <span class="n">collection</span><span class="o">.</span><span class="na">getElements</span><span class="o">();</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="n">actualTexts</span> <span class="o">=</span> <span class="nc">ElementsCollection</span><span class="o">.</span><span class="na">texts</span><span class="o">(</span><span class="n">elements</span><span class="o">);</span> <span class="kt">boolean</span> <span class="n">allMatched</span> <span class="o">=</span> <span class="n">webElements</span><span class="o">.</span><span class="na">stream</span><span class="o">()</span> <span class="o">.</span><span class="na">map</span><span class="o">(</span><span class="n">webElement</span> <span class="o">-&gt;</span> <span class="n">webElement</span><span class="o">.</span><span class="na">getText</span><span class="o">().</span><span class="na">startsWith</span><span class="o">(</span><span class="s">"Z"</span><span class="o">))</span> <span class="o">.</span><span class="na">reduce</span><span class="o">(</span><span class="kc">true</span><span class="o">,</span> <span class="o">(</span><span class="n">x</span><span class="o">,</span> <span class="n">y</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="n">x</span> <span class="o">&amp;&amp;</span> <span class="n">y</span><span class="o">);</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">CheckResult</span><span class="o">(</span><span class="n">allMatched</span><span class="o">,</span> <span class="n">actualTexts</span><span class="o">);</span> <span class="o">}</span> <span class="o">}</span> <span class="err">$$</span><span class="o">(</span><span class="s">".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&amp;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&amp;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> https://selenide.org/2023/05/29/selenide-6.15.0/ https://selenide.org/2023/05/29/selenide-6.15.0 2023-05-29T00:00:00+00:00 Released 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">,()-&gt;{</span> <span class="n">open</span><span class="o">(</span><span class="s">"/login.asp"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#username"</span><span class="o">).</span><span class="na">val</span><span class="o">(</span><span class="s">"u"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#password"</span><span class="o">).</span><span class="na">val</span><span class="o">(</span><span class="s">"p"</span><span class="o">);</span> <span class="o">});</span> <span class="n">step</span><span class="o">(</span><span class="s">"logout"</span><span class="o">,()-&gt;{</span> <span class="err">$</span><span class="o">(</span><span class="s">"#logout"</span><span class="o">).</span><span class="na">click</span><span class="o">();</span> <span class="err">$</span><span class="o">(</span><span class="s">"#goodBye"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Good bye looser!"</span><span class="o">));</span> <span class="o">});</span> <span class="o">}</span> </code></pre></div></div> <p>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> https://selenide.org/2023/05/08/selenide-6.14.0/ https://selenide.org/2023/05/08/selenide-6.14.0 2023-05-08T00:00:00+00:00 Released 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">-&gt;</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">-&gt;</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 -&gt; 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">-&gt;</span> <span class="o">{</span> <span class="n">open</span><span class="o">(</span><span class="s">"https://site.com/login/as/admin"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="n">by</span><span class="o">(</span><span class="s">"value"</span><span class="o">,</span> <span class="s">"bob"</span><span class="o">)).</span><span class="na">find</span><span class="o">(</span><span class="s">"[name=is_admin]"</span><span class="o">).</span><span class="na">setEnabled</span><span class="o">();</span> <span class="o">});</span> <span class="err">$</span><span class="o">(</span><span class="s">"h1"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Hello, chat admin!"</span><span class="o">));</span> </code></pre></div></div> <p>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">&lt;select&gt;</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">--&gt;</span> <span class="nl">JavascriptException:</span> <span class="n">javascript</span> <span class="nl">error:</span> <span class="n">undefined</span> <span class="n">is</span> <span class="n">not</span> <span class="nf">iterable</span> <span class="o">(</span><span class="n">cannot</span> <span class="n">read</span> <span class="n">property</span> <span class="nf">Symbol</span><span class="o">(</span><span class="nc">Symbol</span><span class="o">.</span><span class="na">iterator</span><span class="o">))</span> </code></pre></div></div> <p>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&lt;SelenideElement&gt;</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&amp;ab_channel=Jfokus">Flaky tests</a></li> <li><a href="https://www.youtube.com/watch?v=wN45Qla66-o&amp;list=PLFGoYjJG_fqrvWt1FfHqKoREQmSPxazBq&amp;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> https://selenide.org/2023/04/04/selenide-6.13.0/ https://selenide.org/2023/04/04/selenide-6.13.0 2023-04-04T00:00:00+00:00 Released 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">-&gt;</span> <span class="o">{</span> <span class="n">banner</span><span class="o">.</span><span class="na">find</span><span class="o">(</span><span class="s">".title"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"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&amp;ab_channel=OlehPendrak">Selenide - UI Automation Tool</a> by Naveen AutomationLabs</li> <li><a href="https://www.youtube.com/watch?v=18J2_4a4Cl4&amp;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> https://selenide.org/2023/04/01/selenide-6.13.0/ https://selenide.org/2023/04/01/selenide-6.13.0 2023-04-01T00:00:00+00:00 Released 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&amp;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> https://selenide.org/2023/03/23/selenide-6.12.4/ https://selenide.org/2023/03/23/selenide-6.12.4 2023-03-23T00:00:00+00:00 Released 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> https://selenide.org/2023/03/09/selenide-6.12.2/ https://selenide.org/2023/03/09/selenide-6.12.2 2023-03-09T00:00:00+00:00 Released 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&amp;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> https://selenide.org/2023/02/24/selenide-6.12.0/ https://selenide.org/2023/02/24/selenide-6.12.0 2023-02-24T00:00:00+00:00 Released 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> https://selenide.org/2023/01/20/selenide-6.11.1/ https://selenide.org/2023/01/20/selenide-6.11.1 2023-01-20T00:00:00+00:00 Released 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> https://selenide.org/2023/01/03/selenide-6.11.0/ https://selenide.org/2023/01/03/selenide-6.11.0 2023-01-03T00:00:00+00:00 Released 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&amp;list=PL9ok7C7Yn9A9YyRISFrxHdaxb5qqrxp_i&amp;index=4&amp;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> https://selenide.org/2022/12/08/selenide-6.10.2/ https://selenide.org/2022/12/08/selenide-6.10.2 2022-12-08T00:00:00+00:00 Released 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&amp;ab_channel=DEVCLUB.EE&amp;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">&lt;select&gt;</code> options using JavaScript</h3> <p>It should made work with <code class="language-plaintext highlighter-rouge">&lt;select&gt;</code>s faster. As a bonus, now Selenide throws a more detailed exception if <code class="language-plaintext highlighter-rouge">&lt;select&gt;</code> (or <code class="language-plaintext highlighter-rouge">&lt;option&gt;</code>) was <code class="language-plaintext highlighter-rouge">disabled</code>.</p> <p>Given a <code class="language-plaintext highlighter-rouge">&lt;select&gt;</code> with some disabled options:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;select</span> <span class="na">id=</span><span class="s">"region"</span><span class="nt">&gt;</span> <span class="nt">&lt;option</span> <span class="na">value=</span><span class="s">"belgorod"</span><span class="nt">&gt;</span>Belgorod<span class="nt">&lt;/option&gt;</span> <span class="nt">&lt;option</span> <span class="na">value=</span><span class="s">"kherson"</span> <span class="na">disabled</span><span class="nt">&gt;</span>Kherson<span class="nt">&lt;/option&gt;</span> <span class="nt">&lt;option</span> <span class="na">value=</span><span class="s">"zaporozhia"</span> <span class="na">disabled</span><span class="nt">&gt;</span>Zaporozhia<span class="nt">&lt;/option&gt;</span> <span class="nt">&lt;/select&gt;</span> </code></pre></div></div> <p>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> https://selenide.org/2022/11/21/selenide-6.10.0/ https://selenide.org/2022/11/21/selenide-6.10.0 2022-11-21T00:00:00+00:00 Released 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">-&gt;</span> <span class="s">"{votes: 2133326, for: 99.23, against: 0.77}"</span><span class="o">);</span> <span class="n">open</span><span class="o">(</span><span class="s">"https://referendum.ru"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#votesFor"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"99.23%"</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">"#h3"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"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> -&gt; <code class="language-plaintext highlighter-rouge">192.168.0.18</code></li> <li><code class="language-plaintext highlighter-rouge">ClientUtil.getConnectableAddress()</code> -&gt; <code class="language-plaintext highlighter-rouge">127.0.0.1</code></li> </ul> <p>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&amp;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> https://selenide.org/2022/10/07/selenide-6.9.0/ https://selenide.org/2022/10/07/selenide-6.9.0 2022-10-07T00:00:00+00:00 Released 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> https://selenide.org/2022/09/27/selenide-6.8.1/ https://selenide.org/2022/09/27/selenide-6.8.1 2022-09-27T00:00:00+00:00 Released 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> https://selenide.org/2022/09/24/selenide-6.8.0/ https://selenide.org/2022/09/24/selenide-6.8.0 2022-09-24T00:00:00+00:00 Released 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&amp;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&amp;list=PL6AdzyjjD5HC4NJuc083bzFq86JekmASF&amp;ab_channel=AutomationBro-DilpreetJohal">Selenide Java Tutorial Series</a> by <a href="https://www.youtube.com/c/AutomationBro">Dilpreet Johal</a></li> <li><a href="https://mszeles.com/save-dozens-of-minutes-daily-during-writing-selenide-and-selenium-e2e-automated-tests-using-the-selenideium-element-inspector-chrome-extension">Selenideium Element Inspector</a> by <a href="https://hashnode.com/@mszeles">Miki Szeles</a></li> <li><a href="https://mszeles.com/selenium-javascript-python-c-cypress-testcafe-playwright-squish-selector-generation-has-been-added-to-selenideium-element-inspector-v20">Selenideium Element Inspector 2.0</a> by <a href="https://hashnode.com/@mszeles">Miki Szeles</a></li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2022/09/05/selenide-6.7.4/ https://selenide.org/2022/09/05/selenide-6.7.4 2022-09-05T00:00:00+00:00 Released 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">&lt;select&gt;</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">&lt;option&gt;</code> in a <code class="language-plaintext highlighter-rouge">&lt;select&gt;</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">&lt;select&gt;</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> https://selenide.org/2022/08/27/selenide-6.7.3/ https://selenide.org/2022/08/27/selenide-6.7.3 2022-08-27T00:00:00+00:00 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> https://selenide.org/2022/08/22/selenide-puzzler/ https://selenide.org/2022/08/22/selenide-puzzler 2022-08-22T00:00:00+00:00 Released 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">&lt;</span> <span class="mi">1000</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span> <span class="n">open</span><span class="o">(</span><span class="s">"about:blank"</span><span class="o">);</span> <span class="n">closeWebDriver</span><span class="o">();</span> <span class="o">}</span> </code></pre></div></div> <p>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&amp;t=318s&amp;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> https://selenide.org/2022/08/14/selenide-6.7.2/ https://selenide.org/2022/08/14/selenide-6.7.2 2022-08-14T00:00:00+00:00 Released 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">&lt;div</span> <span class="na">id=</span><span class="s">"freedom-to"</span><span class="nt">&gt;</span>Britney Spears<span class="nt">&lt;/div&gt;</span> </code></pre></div></div> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"#freedom-to"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Brit"</span><span class="o">));</span> <span class="c1">// was OK</span> </code></pre></div></div> <p>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&amp;list=PL9Z-JgiTsOYRfoG_mcRBlTUIFPIknhQ6S">Extending open-source libraries: Selenide &amp; Selenium</a> - Selenium Conf, 30.07.2022</li> <li><a href="https://www.youtube.com/watch?v=-c5XT2v5gRY&amp;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> https://selenide.org/2022/08/04/selenide-6.7.0/ https://selenide.org/2022/08/04/selenide-6.7.0 2022-08-04T00:00:00+00:00 Released 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> https://selenide.org/2022/07/01/selenide-6.6.6/ https://selenide.org/2022/07/01/selenide-6.6.6 2022-07-01T00:00:00+00:00 Released 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> https://selenide.org/2022/06/20/selenide-6.6.4/ https://selenide.org/2022/06/20/selenide-6.6.4 2022-06-20T00:00:00+00:00 Released 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> https://selenide.org/2022/06/12/selenide-6.6.3/ https://selenide.org/2022/06/12/selenide-6.6.3 2022-06-12T00:00:00+00:00 Released 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” -&gt; “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 -&gt; 4.2.1</a>.</li> <li>WebDriverManager <a href="https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md">5.1.1 -&gt; 5.2.0</a></li> </ul> <p><br /></p> <h3 id="statistics">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> https://selenide.org/2022/06/08/selenide-6.6.0/ https://selenide.org/2022/06/08/selenide-6.6.0 2022-06-08T00:00:00+00:00 Released 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">&lt;input type=date&gt;</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">&lt;input type=date&gt;</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">&lt;input&gt;</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 -&gt; 4.1.4</a>.</li> <li>WebDriverManager <a href="https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md">5.1.0 -&gt; 5.1.1</a></li> <li>Netty <a href="https://netty.io/news/2022/04/12/4-1-76-Final.html">4.1.75.Final -&gt; 4.1.76.Final</a></li> <li>Netty <a href="https://netty.io/news/2022/05/06/2-1-77-Final.html">4.1.76.Final -&gt; 4.1.77.Final</a></li> <li>LittleProxy <a href="https://github.com/LittleProxy/LittleProxy/releases">2.0.7 -&gt; 2.0.9</a></li> </ul> <p>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 -&gt; Delete” instead of “Home -&gt; Shift+A -&gt; 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> https://selenide.org/2022/05/17/selenide-6.5.0/ https://selenide.org/2022/05/17/selenide-6.5.0 2022-05-17T00:00:00+00:00 Released 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> https://selenide.org/2022/04/07/selenide-6.4.0/ https://selenide.org/2022/04/07/selenide-6.4.0 2022-04-07T00:00:00+00:00 Released 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> https://selenide.org/2022/02/07/selenide-6.3.0/ https://selenide.org/2022/02/07/selenide-6.3.0 2022-02-07T00:00:00+00:00 Released 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 “&lt;Click to see difference&gt;” 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 “&lt;Click to see difference&gt;” 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(&lt;condition&gt;)</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&lt;SelenideElement&gt;</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 &amp; 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> https://selenide.org/2022/01/10/selenide-6.2.0/ https://selenide.org/2022/01/10/selenide-6.2.0 2022-01-10T00:00:00+00:00 Released 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> https://selenide.org/2021/11/24/selenide-6.1.1/ https://selenide.org/2021/11/24/selenide-6.1.1 2021-11-24T00:00:00+00:00 Released 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> https://selenide.org/2021/11/23/selenide-6.1.0/ https://selenide.org/2021/11/23/selenide-6.1.0 2021-11-23T00:00:00+00:00 Released 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> -&gt; <code class="language-plaintext highlighter-rouge">ElementsCollection.shouldHave(size())</code></li> <li><code class="language-plaintext highlighter-rouge">$.waitUntil(_, timeout)</code> -&gt; <code class="language-plaintext highlighter-rouge">$.should(_, Duration.ofMillis(timeout))</code></li> <li><code class="language-plaintext highlighter-rouge">$.waitWhile(_, timeout)</code> -&gt; <code class="language-plaintext highlighter-rouge">$.shouldNot(_, Duration.ofMillis(timeout))</code></li> <li><code class="language-plaintext highlighter-rouge">Condition.disappears</code> -&gt; <code class="language-plaintext highlighter-rouge">Condition.hidden</code></li> <li><code class="language-plaintext highlighter-rouge">Condition.matchesText</code> -&gt; <code class="language-plaintext highlighter-rouge">Condition.matchText</code></li> <li><code class="language-plaintext highlighter-rouge">Selenide.close</code> -&gt; <code class="language-plaintext highlighter-rouge">Selenide.closeWebDriver()</code> 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">&lt;select&gt;</code> or <code class="language-plaintext highlighter-rouge">&lt;input type=radio&gt;</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> https://selenide.org/2021/10/25/selenide-6.0.1/ https://selenide.org/2021/10/25/selenide-6.0.1 2021-10-25T00:00:00+00:00 Released 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">&lt;Click to see difference&gt;</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> https://selenide.org/2021/09/28/selenide-5.25.0/ https://selenide.org/2021/09/28/selenide-5.25.0 2021-09-28T00:00:00+00:00 Released 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> https://selenide.org/2021/08/29/selenide-5.24.0/ https://selenide.org/2021/08/29/selenide-5.24.0 2021-08-29T00:00:00+00:00 Released 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&lt;String, String&gt; 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> https://selenide.org/2021/07/16/selenide-5.23.0/ https://selenide.org/2021/07/16/selenide-5.23.0 2021-07-16T00:00:00+00:00 Released 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> https://selenide.org/2021/07/05/selenide-5.22.3/ https://selenide.org/2021/07/05/selenide-5.22.3 2021-07-05T00:00:00+00:00 Released 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">-&gt;</span> <span class="o">{</span> <span class="c1">// add cookies</span> <span class="n">link</span><span class="o">.</span><span class="na">click</span><span class="o">();</span> <span class="c1">// driver.switchTo().window();</span> <span class="c1">// alert.dismiss();</span> <span class="c1">// send http request</span> <span class="c1">// call api</span> <span class="o">}));</span> </code></pre></div></div> <p>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">&lt;select&gt;</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&amp;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> https://selenide.org/2021/06/08/selenide-5.22.0/ https://selenide.org/2021/06/08/selenide-5.22.0 2021-06-08T00:00:00+00:00 Released 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> https://selenide.org/2021/05/15/selenide-5.21.0/ https://selenide.org/2021/05/15/selenide-5.21.0 2021-05-15T00:00:00+00:00 Released 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> https://selenide.org/2021/03/23/selenide-5.20.1/ https://selenide.org/2021/03/23/selenide-5.20.1 2021-03-23T00:00:00+00:00 Released 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> https://selenide.org/2021/02/24/selenide-5.19.0/ https://selenide.org/2021/02/24/selenide-5.19.0 2021-02-24T00:00:00+00:00 Released 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> https://selenide.org/2021/02/11/selenide-5.18.1/ https://selenide.org/2021/02/11/selenide-5.18.1 2021-02-11T00:00:00+00:00 Released 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> https://selenide.org/2021/01/23/selenide-5.18.0/ https://selenide.org/2021/01/23/selenide-5.18.0 2021-01-23T00:00:00+00:00 Released 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> https://selenide.org/2020/12/30/selenide-5.17.2/ https://selenide.org/2020/12/30/selenide-5.17.2 2020-12-30T00:00:00+00:00 Released 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&lt;ElementsContainer&gt;</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&lt;ElementsContainer&gt;</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> https://selenide.org/2020/12/26/selenide-5.17.0/ https://selenide.org/2020/12/26/selenide-5.17.0 2020-12-26T00:00:00+00:00 Released 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&amp;feature=youtu.be&amp;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> https://selenide.org/2020/11/25/selenide-5.16.2/ https://selenide.org/2020/11/25/selenide-5.16.2 2020-11-25T00:00:00+00:00 Released 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">&lt;</span><span class="n">div</span> <span class="n">id</span><span class="o">=</span><span class="s">"child_div1"</span><span class="o">&gt;</span><span class="nc">Son</span><span class="o">&lt;/</span><span class="n">div</span><span class="o">&gt;</span><span class="err">'</span> </code></pre></div></div> <p>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">&lt;</span><span class="n">div</span> <span class="n">id</span><span class="o">=</span><span class="s">"child_div1"</span><span class="o">&gt;</span><span class="nc">Son</span><span class="o">&lt;/</span><span class="n">div</span><span class="o">&gt;</span><span class="err">'</span> <span class="nc">Actual</span> <span class="nl">value:</span> <span class="nc">Son</span> </code></pre></div></div> <p>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">--&gt;</span> <span class="nc">IllegalArgumentException</span><span class="o">(</span><span class="s">"File name cannot contain slash: 11/08/2020_-_day_transactions.pdf"</span><span class="o">)</span> </code></pre></div></div> <p>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> https://selenide.org/2020/11/20/selenide-5.16.0/ https://selenide.org/2020/11/20/selenide-5.16.0 2020-11-20T00:00:00+00:00 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 -&gt; 4.1.54.Final +--- xyz.rogfam:littleproxy:2.0.0-beta-5 | +--- io.netty:netty-all:4.1.34.Final -&gt; 4.1.54.Final </code></pre></div></div> <p>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> https://selenide.org/2020/11/17/why-proxy-does-not-work-in-selenoid/ https://selenide.org/2020/11/17/why-proxy-does-not-work-in-selenoid 2020-11-17T00:00:00+00:00 Released 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 &lt;li&gt; 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">&lt;</span> <span class="mi">10</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span> <span class="n">list</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">i</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">visible</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>Assume that there is 100 <code class="language-plaintext highlighter-rouge">&lt;li&gt;</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">&lt;</span> <span class="mi">10</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span> <span class="n">unfiltered</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">i</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">visible</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>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">&lt;N&gt;</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">&lt;</span> <span class="mi">10</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span> <span class="n">list</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">i</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">visible</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>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">&lt;a&gt;</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&amp;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> https://selenide.org/2020/09/26/selenide-5.15.0/ https://selenide.org/2020/09/26/selenide-5.15.0 2020-09-26T00:00:00+00:00 Released 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> https://selenide.org/2020/08/17/selenide-5.14.0/ https://selenide.org/2020/08/17/selenide-5.14.0 2020-08-17T00:00:00+00:00 Released 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">&lt;form&gt;</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">&lt;h1&gt;Hello World&lt;/h1&gt;</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">&lt;form&gt;</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">&lt;input&gt;</code> to be inside of <code class="language-plaintext highlighter-rouge">&lt;form&gt;</code>. This is reasonable, but for some reason there are inputs that exist outside of <code class="language-plaintext highlighter-rouge">&lt;form&gt;</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">&lt;a href&gt;</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> https://selenide.org/2020/07/08/selenide-5.13.0/ https://selenide.org/2020/07/08/selenide-5.13.0 2020-07-08T00:00:00+00:00 Released 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> https://selenide.org/2020/05/29/selenide-5.12.2/ https://selenide.org/2020/05/29/selenide-5.12.2 2020-05-29T00:00:00+00:00 Released 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&amp;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> https://selenide.org/2020/05/25/selenide-5.12.1/ https://selenide.org/2020/05/25/selenide-5.12.1 2020-05-25T00:00:00+00:00 Released 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&amp;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> https://selenide.org/2020/05/23/selenide-5.12.0/ https://selenide.org/2020/05/23/selenide-5.12.0 2020-05-23T00:00:00+00:00 Released 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&amp;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> https://selenide.org/2020/04/21/selenide-5.11.1/ https://selenide.org/2020/04/21/selenide-5.11.1 2020-04-21T00:00:00+00:00 Released 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">&lt;h1&gt;</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">&lt;h1&gt;</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> https://selenide.org/2020/04/19/selenide-5.11.0/ https://selenide.org/2020/04/19/selenide-5.11.0 2020-04-19T00:00:00+00:00 Released 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&amp;list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe&amp;index=35">Flaky tests: The method</a></li> <li><a href="https://www.youtube.com/watch?v=RmaTYY3B-Wg&amp;list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe&amp;index=41">BOF: Glorious past and promising future of Selenide</a></li> <li><a href="https://www.youtube.com/watch?v=4vI4Z6sE7OA&amp;list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe&amp;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> https://selenide.org/2020/03/18/selenide-5.10.0/ https://selenide.org/2020/03/18/selenide-5.10.0 2020-03-18T00:00:00+00:00 Released 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> https://selenide.org/2020/03/10/selenide-5.9.0/ https://selenide.org/2020/03/10/selenide-5.9.0 2020-03-10T00:00:00+00:00 Released 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">-&gt;</span> <span class="n">el</span><span class="o">.</span><span class="na">getAttribute</span><span class="o">(</span><span class="s">"border"</span><span class="o">).</span><span class="na">equals</span><span class="o">(</span><span class="s">"1"</span><span class="o">)));</span> </code></pre></div></div> <p>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">-&gt;</span> <span class="n">el</span><span class="o">.</span><span class="na">getAttribute</span><span class="o">(</span><span class="s">"value"</span><span class="o">).</span><span class="na">equals</span><span class="o">(</span><span class="s">"dog"</span><span class="o">)));</span> <span class="err">$$</span><span class="o">(</span><span class="s">"input"</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">allMatch</span><span class="o">(</span><span class="s">"value==cat"</span><span class="o">,</span> <span class="n">el</span> <span class="o">-&gt;</span> <span class="n">el</span><span class="o">.</span><span class="na">getAttribute</span><span class="o">(</span><span class="s">"value"</span><span class="o">).</span><span class="na">equals</span><span class="o">(</span><span class="s">"cat"</span><span class="o">)));</span> <span class="err">$$</span><span class="o">(</span><span class="s">"input"</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">noneMatch</span><span class="o">(</span><span class="s">"value==bird"</span><span class="o">,</span> <span class="n">el</span> <span class="o">-&gt;</span> <span class="n">el</span><span class="o">.</span><span class="na">getAttribute</span><span class="o">(</span><span class="s">"value"</span><span class="o">).</span><span class="na">equals</span><span class="o">(</span><span class="s">"bird"</span><span class="o">)));</span> </code></pre></div></div> <p>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> https://selenide.org/2020/02/28/selenide-5.8.0/ https://selenide.org/2020/02/28/selenide-5.8.0 2020-02-28T00:00:00+00:00 Released 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> https://selenide.org/2020/02/07/selenide-5.7.0/ https://selenide.org/2020/02/07/selenide-5.7.0 2020-02-07T00:00:00+00:00 Released 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> https://selenide.org/2020/01/14/selenide-5.6.1/ https://selenide.org/2020/01/14/selenide-5.6.1 2020-01-14T00:00:00+00:00 Released 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> https://selenide.org/2019/12/26/selenide-5.6.0/ https://selenide.org/2019/12/26/selenide-5.6.0 2019-12-26T00:00:00+00:00 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">&lt;select&gt;</code> with custom home-made “nice”/”usable” elements, made from bunch of <code class="language-plaintext highlighter-rouge">&lt;div&gt;</code>s, <code class="language-plaintext highlighter-rouge">&lt;span&gt;</code>s, <code class="language-plaintext highlighter-rouge">&lt;li&gt;</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">&lt;select&gt;</code>. We tried hard, but failed to clicks all those <code class="language-plaintext highlighter-rouge">&lt;div&gt;</code>s and <code class="language-plaintext highlighter-rouge">&lt;span&gt;</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> https://selenide.org/2019/12/24/advent-calendar-javascript-tricks/ https://selenide.org/2019/12/24/advent-calendar-javascript-tricks 2019-12-24T00:00:00+00:00 Defaŭlta lingvo <h1 id="defaŭlta-lingvo">Defaŭlta lingvo</h1> <p>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">&lt;plugin&gt;</span> <span class="nt">&lt;artifactId&gt;</span>maven-surefire-plugin<span class="nt">&lt;/artifactId&gt;</span> <span class="nt">&lt;version&gt;</span>2.xx.yy<span class="nt">&lt;/version&gt;</span> <span class="nt">&lt;configuration&gt;</span> <span class="nt">&lt;systemPropertyVariables&gt;</span> ... <span class="nt">&lt;chromeoptions.prefs&gt;</span>intl.accept_languages=de<span class="nt">&lt;/chromeoptions.prefs&gt;</span> <span class="nt">&lt;/systemPropertyVariables&gt;</span> <span class="nt">&lt;/configuration&gt;</span> <span class="nt">&lt;/plugin&gt;</span> ... </code></pre></div></div> <h3 id="gradle">Gradle</h3> <p>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> https://selenide.org/2019/12/22/advent-calendar-defaulta-lingvo/ https://selenide.org/2019/12/22/advent-calendar-defaulta-lingvo 2019-12-22T00:00:00+00:00 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">&lt;</span><span class="n">timeOutForElement</span><span class="o">&gt;))</span> <span class="o">.</span><span class="na">until</span><span class="o">(</span><span class="nc">ExpectedConditions</span><span class="o">.</span><span class="na">presenceOfElementLocated</span><span class="o">(</span><span class="nc">By</span><span class="o">.</span><span class="na">cssSelector</span><span class="o">(&lt;</span><span class="n">cssSelector</span><span class="o">&gt;)));</span> </code></pre></div></div> <p>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">&lt;</span><span class="n">timeOutForElement</span><span class="o">&gt;))</span> <span class="o">.</span><span class="na">until</span><span class="o">(</span><span class="nc">ExpectedConditions</span><span class="o">.</span><span class="na">visibilityOfElementLocated</span><span class="o">(</span><span class="nc">By</span><span class="o">.</span><span class="na">cssSelector</span><span class="o">(&lt;</span><span class="n">cssSelector</span><span class="o">&gt;)));</span> </code></pre></div></div> <p>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">(&lt;</span><span class="n">cssSelector</span><span class="o">&gt;).</span><span class="na">should</span><span class="o">(</span><span class="n">exist</span><span class="o">);</span> <span class="n">element</span> <span class="o">=</span> <span class="err">$</span><span class="o">(&lt;</span><span class="n">cssSelector</span><span class="o">&gt;).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">visible</span><span class="o">);</span> </code></pre></div></div> <p><strong>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 like to upload file and check the state of an element to make sure that action succeeded. But how do we know when the element will change its state? The uploading and processing time can be different depending on the file’s size. This is the moment where a lot of people would use <code class="language-plaintext highlighter-rouge">Thread.sleep()</code> if standard Selenium methods failed(it really happens, sometimes Selenium checks the state of some element and thinks that it’s just wrong).</p> <p>With Selenide, we have a very smart tool for this purpose:</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">shouldHave</span><span class="o">(</span><span class="n">exactText</span><span class="o">(&lt;</span><span class="n">expectedText</span><span class="o">&gt;));</span> </code></pre></div></div> <p>This way Selenide will wait for the default timeout period for the element to change its state. We can check it with no additional lines of code and we can be sure that Selenide will really wait for it.</p> <h3 id="whats-next">What’s next?</h3> <p>These are just very basic ideas and examples on how to “wait” with Selenide. There are many more ways of doing it, and the fact is that now we have a lot of powerful tools to write our tests with real and effective waits that don’t need to be fixed with additional “sleeps”. It’s up to you what assertions will be added to your tests. Just make it smart and don’t waste the time, it’s a valuable thing :)</p> <p>Maciej Grymuza (figrym@gmail.com)</p> https://selenide.org/2019/12/20/advent-calendar-big-wait-theory/ https://selenide.org/2019/12/20/advent-calendar-big-wait-theory 2019-12-20T00:00:00+00:00 How to get network data with proxy <p>Good night!</p> <p>In two previous posts of our Selenide Advent Calendar, we tried to find a way to read requests/responses between browser and server. <br /> They both were not ideal because they cannot read BODY of requests and responses.</p> <p>Finally, we try a third way - using a Selenide built-in proxy server.</p> <h3 id="before-test">Before test</h3> <p>As you know, Selenide already has built-in proxy server. You only need to enable 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">proxyEnabled</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span> </code></pre></div></div> <p>Now you need to say the proxy to start tracking requests:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">BrowserMobProxy</span> <span class="n">bmp</span> <span class="o">=</span> <span class="nc">WebDriverRunner</span><span class="o">.</span><span class="na">getSelenideProxy</span><span class="o">().</span><span class="na">getProxy</span><span class="o">();</span> <span class="c1">// remember body of requests (body is not stored by default because it can be large)</span> <span class="n">bmp</span><span class="o">.</span><span class="na">setHarCaptureTypes</span><span class="o">(</span><span class="nc">CaptureType</span><span class="o">.</span><span class="na">getAllContentCaptureTypes</span><span class="o">());</span> <span class="c1">// remember both requests and responses</span> <span class="n">bmp</span><span class="o">.</span><span class="na">enableHarCaptureTypes</span><span class="o">(</span><span class="nc">CaptureType</span><span class="o">.</span><span class="na">REQUEST_CONTENT</span><span class="o">,</span> <span class="nc">CaptureType</span><span class="o">.</span><span class="na">RESPONSE_CONTENT</span><span class="o">);</span> <span class="c1">// start recording!</span> <span class="n">bmp</span><span class="o">.</span><span class="na">newHar</span><span class="o">(</span><span class="s">"pofig"</span><span class="o">);</span> </code></pre></div></div> <h3 id="after-test">After test</h3> <p>Now you need to get a HAR and analyze its entries:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">HarEntry</span><span class="o">&gt;</span> <span class="n">requests</span> <span class="o">=</span> <span class="n">bmp</span><span class="o">.</span><span class="na">getHar</span><span class="o">().</span><span class="na">getLog</span><span class="o">().</span><span class="na">getEntries</span><span class="o">();</span> </code></pre></div></div> <p>HAR (HTTP Archive) is like an “archive” with all network requests recorded during the test run.</p> <p>Every entry in it is a network request.<br /> It has everything needed inside: URL, request and response, their http status and body.<br /> Everything that we dreamed about.</p> <p><img src="/images/2019/12/har.entries.png" alt="HAR entries" /></p> <h3 id="pros">Pros:</h3> <ul> <li>It has all data you needed</li> <li>It’s easy to analyze it programmatically</li> <li>Works in all browsers</li> </ul> <h3 id="cons">Cons:</h3> <p>There is only one possible problem. When you run tests and browsers on different machines, and the “tests” machine is not accessible from the “browsers” machine, it’s just technically impossible to use proxy server.<br /> Though I never understood why people make things that complex.</p> <p>People, just run tests and browsers on the same machine. Everything will get MUCH SIMPLER! <br /> If you need to parallelize - just parallelize TESTS.<br /> If you need a cluster (grid) - just run TESTS on different cluster nodes (and they will run their browsers locally).<br /> There is no reasons to make it more complex.</p> <h2 id="whats-now">What’s now?</h2> <p>Now we can read network data during tests run.<br /> But I hope you don’t really use it often. Usually it should not be needed. Maybe in very rare cases. <br /> Usually it should be enough to just read application logs to understand what requests were sent to server.</p> <p>Keep it simple.</p> <p><br /> <a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2019/12/18/advent-calendar-network-logs-with-proxy/ https://selenide.org/2019/12/18/advent-calendar-network-logs-with-proxy 2019-12-18T00:00:00+00:00 How to get network data with JavaScript <p>Good night!</p> <p>In the yesterday post we tried to get browser logs with “goog:loggingPrefs” capability.<br /> Now we will try to get browser network data with JavaScript.</p> <p>It’s simple. We just need to call this JavaScript in the end of test:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">String</span> <span class="n">js</span> <span class="o">=</span> <span class="s">"var performance = window.performance || window.mozPerformance"</span> <span class="o">+</span> <span class="s">" || window.msPerformance || window.webkitPerformance || {};"</span> <span class="o">+</span> <span class="s">" return performance.getEntries() || {};"</span><span class="o">;</span> <span class="nc">String</span> <span class="n">netData</span> <span class="o">=</span> <span class="n">executeJavaScript</span><span class="o">(</span><span class="n">js</span><span class="o">).</span><span class="na">toString</span><span class="o">();</span> <span class="n">logger</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"Network traffic: {}"</span><span class="o">,</span> <span class="n">netData</span><span class="o">);</span> </code></pre></div></div> <p>The result looks like this:</p> <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">Network</span><span class="w"> </span><span class="err">traffic:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="p">{</span><span class="err">name=https://selenide.org/quick-start.html</span><span class="p">,</span><span class="w"> </span><span class="err">connectEnd=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">connectStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">decodedBodySize=</span><span class="mi">32582</span><span class="p">,</span><span class="w"> </span><span class="err">domComplete=</span><span class="mi">724</span><span class="p">,</span><span class="w"> </span><span class="err">domContentLoadedEventEnd=</span><span class="mi">119</span><span class="p">,</span><span class="w"> </span><span class="err">domContentLoadedEventStart=</span><span class="mi">115</span><span class="p">,</span><span class="w"> </span><span class="err">domInteractive=</span><span class="mi">104</span><span class="p">,</span><span class="w"> </span><span class="err">domainLookupEnd=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">domainLookupStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">duration=</span><span class="mi">724</span><span class="p">,</span><span class="w"> </span><span class="err">encodedBodySize=</span><span class="mi">32582</span><span class="p">,</span><span class="w"> </span><span class="err">entryType=navigation</span><span class="p">,</span><span class="w"> </span><span class="err">fetchStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">initiatorType=navigation</span><span class="p">,</span><span class="w"> </span><span class="err">loadEventEnd=</span><span class="mi">724</span><span class="p">,</span><span class="w"> </span><span class="err">loadEventStart=</span><span class="mi">724</span><span class="p">,</span><span class="w"> </span><span class="err">nextHopProtocol=http/</span><span class="mf">1.1</span><span class="p">,</span><span class="w"> </span><span class="err">redirectCount=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">redirectEnd=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">redirectStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">requestStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">responseEnd=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">responseStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">secureConnectionStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">serverTiming=</span><span class="p">[],</span><span class="w"> </span><span class="err">startTime=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">transferSize=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">type=navigate</span><span class="p">,</span><span class="w"> </span><span class="err">unloadEventEnd=</span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="err">unloadEventStart=</span><span class="mi">9</span><span class="p">,</span><span class="w"> </span><span class="err">workerStart=</span><span class="mi">0</span><span class="p">},</span><span class="w"> </span><span class="p">{</span><span class="err">name=https://selenide.org/assets/themes/ingmar/css/styles.css?</span><span class="mi">001</span><span class="p">,</span><span class="w"> </span><span class="err">connectEnd=</span><span class="mi">12</span><span class="p">,</span><span class="w"> </span><span class="err">connectStart=</span><span class="mi">12</span><span class="p">,</span><span class="w"> </span><span class="err">decodedBodySize=</span><span class="mi">8177</span><span class="p">,</span><span class="w"> </span><span class="err">domainLookupEnd=</span><span class="mi">12</span><span class="p">,</span><span class="w"> </span><span class="err">domainLookupStart=</span><span class="mi">12</span><span class="p">,</span><span class="w"> </span><span class="err">duration=</span><span class="mi">29</span><span class="p">,</span><span class="w"> </span><span class="err">encodedBodySize=</span><span class="mi">8177</span><span class="p">,</span><span class="w"> </span><span class="err">entryType=resource</span><span class="p">,</span><span class="w"> </span><span class="err">fetchStart=</span><span class="mi">12</span><span class="p">,</span><span class="w"> </span><span class="err">initiatorType=link</span><span class="p">,</span><span class="w"> </span><span class="err">nextHopProtocol=http/</span><span class="mf">1.1</span><span class="p">,</span><span class="w"> </span><span class="err">redirectEnd=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">redirectStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">requestStart=</span><span class="mi">12</span><span class="p">,</span><span class="w"> </span><span class="err">responseEnd=</span><span class="mi">41</span><span class="p">,</span><span class="w"> </span><span class="err">responseStart=</span><span class="mi">21</span><span class="p">,</span><span class="w"> </span><span class="err">secureConnectionStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">serverTiming=</span><span class="p">[],</span><span class="w"> </span><span class="err">startTime=</span><span class="mi">12</span><span class="p">,</span><span class="w"> </span><span class="err">transferSize=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">workerStart=</span><span class="mi">0</span><span class="p">},</span><span class="w"> </span><span class="p">{</span><span class="err">name=https://ajax.googleapis.com/ajax/libs/jquery/</span><span class="mf">2.1</span><span class="err">.</span><span class="mi">1</span><span class="err">/jquery.min.js</span><span class="p">,</span><span class="w"> </span><span class="err">connectEnd=</span><span class="mi">13</span><span class="p">,</span><span class="w"> </span><span class="err">connectStart=</span><span class="mi">13</span><span class="p">,</span><span class="w"> </span><span class="err">decodedBodySize=</span><span class="mi">84245</span><span class="p">,</span><span class="w"> </span><span class="err">domainLookupEnd=</span><span class="mi">13</span><span class="p">,</span><span class="w"> </span><span class="err">domainLookupStart=</span><span class="mi">13</span><span class="p">,</span><span class="w"> </span><span class="err">duration=</span><span class="mi">28</span><span class="p">,</span><span class="w"> </span><span class="err">encodedBodySize=</span><span class="mi">84245</span><span class="p">,</span><span class="w"> </span><span class="err">entryType=resource</span><span class="p">,</span><span class="w"> </span><span class="err">fetchStart=</span><span class="mi">13</span><span class="p">,</span><span class="w"> </span><span class="err">initiatorType=script</span><span class="p">,</span><span class="w"> </span><span class="err">nextHopProtocol=http/</span><span class="mf">1.1</span><span class="p">,</span><span class="w"> </span><span class="err">redirectEnd=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">redirectStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">requestStart=</span><span class="mi">13</span><span class="p">,</span><span class="w"> </span><span class="err">responseEnd=</span><span class="mi">41</span><span class="p">,</span><span class="w"> </span><span class="err">responseStart=</span><span class="mi">21</span><span class="p">,</span><span class="w"> </span><span class="err">secureConnectionStart=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">serverTiming=</span><span class="p">[],</span><span class="w"> </span><span class="err">startTime=</span><span class="mi">13</span><span class="p">,</span><span class="w"> </span><span class="err">transferSize=</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="err">workerStart=</span><span class="mi">0</span><span class="p">}</span><span class="w"> </span><span class="p">]</span><span class="w"> </span></code></pre></div></div> <h3 id="pros">Pros:</h3> <ul> <li>You don’t need to setup the browser. It works out of the box.</li> <li>It works in all browsers (I guess?)</li> </ul> <h3 id="cons">Cons:</h3> <ul> <li>We still don’t see request body here.</li> <li>It’s not a valid JSON. We cannot parse it with a standard parser. Would need to create some custom parser.</li> </ul> <p>But this option is quite ok to look at and understand what happens.</p> <h2 id="whats-next">What’s next?</h2> <p>Our last hope to get request bodies is built-in proxy server. We will look at it next time.</p> <p><br /> <a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2019/12/17/advent-calendar-browser-logs-with-js/ https://selenide.org/2019/12/17/advent-calendar-browser-logs-with-js 2019-12-17T00:00:00+00:00 How to get browser logs <p>Good evening!</p> <p>We continue our Selenide Advent Calendar.<br /> Today we will try to look into browser “developer tools”.<br /> It may be useful if you want to know what errors happened during test run, or what requests your AUT sent.</p> <p>Chromedriver suggests the following receipt.</p> <h3 id="1-add-a-couple-of-lines-before-opening-a-browser">1. Add a couple of lines before opening a browser:</h3> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">LoggingPreferences</span> <span class="n">logPrefs</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">LoggingPreferences</span><span class="o">();</span> <span class="n">logPrefs</span><span class="o">.</span><span class="na">enable</span><span class="o">(</span><span class="nc">LogType</span><span class="o">.</span><span class="na">BROWSER</span><span class="o">,</span> <span class="nc">Level</span><span class="o">.</span><span class="na">ALL</span><span class="o">);</span> <span class="n">logPrefs</span><span class="o">.</span><span class="na">enable</span><span class="o">(</span><span class="nc">LogType</span><span class="o">.</span><span class="na">PERFORMANCE</span><span class="o">,</span> <span class="nc">Level</span><span class="o">.</span><span class="na">ALL</span><span class="o">);</span> <span class="n">capabilities</span><span class="o">.</span><span class="na">setCapability</span><span class="o">(</span><span class="s">"goog:loggingPrefs"</span><span class="o">,</span> <span class="n">logPrefs</span><span class="o">);</span> </code></pre></div></div> <p>This capability was named “loggingPrefs” until some version of Chrome, and then was renamed to “goog:loggingPrefs”.<br /> Not sure about other browsers.</p> <p>Besides <code class="language-plaintext highlighter-rouge">BROWSER</code> and <code class="language-plaintext highlighter-rouge">PERFORMANCE</code> there are other types too, but I didn’t understand them.</p> <h3 id="2-fetch-the-logs-in-the-end-of-test">2. Fetch the logs in the end of test:</h3> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Logs</span> <span class="n">logs</span> <span class="o">=</span> <span class="n">getWebDriver</span><span class="o">().</span><span class="na">manage</span><span class="o">().</span><span class="na">logs</span><span class="o">();</span> <span class="n">printLog</span><span class="o">(</span><span class="n">logs</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="nc">LogType</span><span class="o">.</span><span class="na">BROWSER</span><span class="o">));</span> <span class="kt">void</span> <span class="nf">printLog</span><span class="o">(</span><span class="nc">LogEntries</span> <span class="n">entries</span><span class="o">)</span> <span class="o">{</span> <span class="n">logger</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"{} log entries found"</span><span class="o">,</span> <span class="n">entries</span><span class="o">.</span><span class="na">getAll</span><span class="o">().</span><span class="na">size</span><span class="o">());</span> <span class="k">for</span> <span class="o">(</span><span class="nc">LogEntry</span> <span class="n">entry</span> <span class="o">:</span> <span class="n">entries</span><span class="o">)</span> <span class="o">{</span> <span class="n">logger</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"{} {} {}"</span><span class="o">,</span> <span class="k">new</span> <span class="nf">Date</span><span class="o">(</span><span class="n">entry</span><span class="o">.</span><span class="na">getTimestamp</span><span class="o">()),</span> <span class="n">entry</span><span class="o">.</span><span class="na">getLevel</span><span class="o">(),</span> <span class="n">entry</span><span class="o">.</span><span class="na">getMessage</span><span class="o">()</span> <span class="o">);</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div></div> <h3 id="3-this-is-how-browser-logs-look-like">3. This is how BROWSER logs look like:</h3> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">BROWSER</span> <span class="nl">logs:</span> <span class="nc">Mon</span> <span class="nc">Dec</span> <span class="mi">16</span> <span class="mi">19</span><span class="o">:</span><span class="mi">29</span><span class="o">:</span><span class="mi">42</span> <span class="no">EET</span> <span class="mi">2019</span> <span class="no">SEVERE</span> <span class="nl">http:</span><span class="c1">//localhost:9126/page/image/payment-promo-campaign-ozon.png - Failed to load resource: the server responded with a status of 404 (Not Found)</span> <span class="nc">Mon</span> <span class="nc">Dec</span> <span class="mi">16</span> <span class="mi">19</span><span class="o">:</span><span class="mi">49</span><span class="o">:</span><span class="mi">14</span> <span class="no">EET</span> <span class="mi">2019</span> <span class="no">INFO</span> <span class="n">console</span><span class="o">-</span><span class="n">api</span> <span class="mi">19</span><span class="o">:</span><span class="mi">16</span> <span class="s">"start loading loans"</span> <span class="nc">Mon</span> <span class="nc">Dec</span> <span class="mi">16</span> <span class="mi">19</span><span class="o">:</span><span class="mi">49</span><span class="o">:</span><span class="mi">14</span> <span class="no">EET</span> <span class="mi">2019</span> <span class="no">INFO</span> <span class="n">console</span><span class="o">-</span><span class="n">api</span> <span class="mi">21</span><span class="o">:</span><span class="mi">18</span> <span class="s">"loaded loans"</span> </code></pre></div></div> <p>Here you can see all logs usually seen at “Developer Tools” -&gt; “Console” tab. Including <code class="language-plaintext highlighter-rouge">console.log</code> messages and JavaScript errors.</p> <h3 id="4-and-this-is-how-performance-logs-look-like">4. And this is how PERFORMANCE logs look like:</h3> <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">PERFORMANCE</span><span class="w"> </span><span class="err">logs:</span><span class="w"> </span><span class="p">{</span><span class="nl">"message"</span><span class="p">:{</span><span class="nl">"method"</span><span class="p">:</span><span class="s2">"Network.loadingFinished"</span><span class="p">,</span><span class="nl">"params"</span><span class="p">:{</span><span class="nl">"encodedDataLength"</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="nl">"requestId"</span><span class="p">:</span><span class="s2">"2C9E49BC49DCD3CA6EA9644255E34DE5"</span><span class="p">,</span><span class="nl">"shouldReportCorbBlocking"</span><span class="p">:</span><span class="kc">false</span><span class="p">,</span><span class="nl">"timestamp"</span><span class="p">:</span><span class="mf">141439.076528</span><span class="p">}},</span><span class="nl">"webview"</span><span class="p">:</span><span class="s2">"FF1A4E4EAAD7143749CD3740DF9BB95F"</span><span class="p">}</span><span class="w"> </span><span class="p">{</span><span class="nl">"message"</span><span class="p">:{</span><span class="nl">"method"</span><span class="p">:</span><span class="s2">"Page.loadEventFired"</span><span class="p">,</span><span class="nl">"params"</span><span class="p">:{</span><span class="nl">"timestamp"</span><span class="p">:</span><span class="mf">141439.234207</span><span class="p">}},</span><span class="nl">"webview"</span><span class="p">:</span><span class="s2">"FF1A4E4EAAD7143749CD3740DF9BB95F"</span><span class="p">}</span><span class="w"> </span><span class="p">{</span><span class="nl">"message"</span><span class="p">:{</span><span class="nl">"method"</span><span class="p">:</span><span class="s2">"Page.frameStoppedLoading"</span><span class="p">,</span><span class="nl">"params"</span><span class="p">:{</span><span class="nl">"frameId"</span><span class="p">:</span><span class="s2">"FF1A4E4EAAD7143749CD3740DF9BB95F"</span><span class="p">}},</span><span class="nl">"webview"</span><span class="p">:</span><span class="s2">"FF1A4E4EAAD7143749CD3740DF9BB95F"</span><span class="p">}</span><span class="w"> </span><span class="p">{</span><span class="nl">"message"</span><span class="p">:{</span><span class="nl">"method"</span><span class="p">:</span><span class="s2">"Page.domContentEventFired"</span><span class="p">,</span><span class="nl">"params"</span><span class="p">:{</span><span class="nl">"timestamp"</span><span class="p">:</span><span class="mf">141439.234834</span><span class="p">}},</span><span class="nl">"webview"</span><span class="p">:</span><span class="s2">"FF1A4E4EAAD7143749CD3740DF9BB95F"</span><span class="p">}</span><span class="w"> </span><span class="p">{</span><span class="nl">"message"</span><span class="p">:{</span><span class="nl">"method"</span><span class="p">:</span><span class="s2">"Page.frameResized"</span><span class="p">,</span><span class="nl">"params"</span><span class="p">:{}},</span><span class="nl">"webview"</span><span class="p">:</span><span class="s2">"FF1A4E4EAAD7143749CD3740DF9BB95F"</span><span class="p">}</span><span class="w"> </span><span class="err">...</span><span class="w"> </span><span class="p">{</span><span class="nl">"message"</span><span class="p">:{</span><span class="nl">"method"</span><span class="p">:</span><span class="s2">"Network.dataReceived"</span><span class="p">,</span><span class="nl">"params"</span><span class="p">:{</span><span class="nl">"dataLength"</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="nl">"encodedDataLength"</span><span class="p">:</span><span class="mi">327</span><span class="p">,</span><span class="nl">"requestId"</span><span class="p">:</span><span class="s2">"58583.71"</span><span class="p">,</span><span class="nl">"timestamp"</span><span class="p">:</span><span class="mf">141474.021635</span><span class="p">}},</span><span class="nl">"webview"</span><span class="p">:</span><span class="s2">"FF1A4E4EAAD7143749CD3740DF9BB95F"</span><span class="p">}</span><span class="w"> </span><span class="p">{</span><span class="nl">"message"</span><span class="p">:{</span><span class="nl">"method"</span><span class="p">:</span><span class="s2">"Network.loadingFinished"</span><span class="p">,</span><span class="nl">"params"</span><span class="p">:{</span><span class="nl">"encodedDataLength"</span><span class="p">:</span><span class="mi">586</span><span class="p">,</span><span class="nl">"requestId"</span><span class="p">:</span><span class="s2">"58583.71"</span><span class="p">,</span><span class="nl">"shouldReportCorbBlocking"</span><span class="p">:</span><span class="kc">false</span><span class="p">,</span><span class="nl">"timestamp"</span><span class="p">:</span><span class="mf">141473.994219</span><span class="p">}},</span><span class="nl">"webview"</span><span class="p">:</span><span class="s2">"FF1A4E4EAAD7143749CD3740DF9BB95F"</span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <h3 id="pros">Pros</h3> <p>Every record is a valid JSON. You can parse and analyze right in your test.</p> <p>This is how the first record looks formatted:</p> <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w"> </span><span class="nl">"message"</span><span class="p">:{</span><span class="w"> </span><span class="nl">"method"</span><span class="p">:</span><span class="s2">"Network.loadingFinished"</span><span class="p">,</span><span class="w"> </span><span class="nl">"params"</span><span class="p">:{</span><span class="w"> </span><span class="nl">"encodedDataLength"</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="nl">"requestId"</span><span class="p">:</span><span class="s2">"2C9E49BC49DCD3CA6EA9644255E34DE5"</span><span class="p">,</span><span class="w"> </span><span class="nl">"shouldReportCorbBlocking"</span><span class="p">:</span><span class="kc">false</span><span class="p">,</span><span class="w"> </span><span class="nl">"timestamp"</span><span class="p">:</span><span class="mf">141439.076528</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="nl">"webview"</span><span class="p">:</span><span class="s2">"FF1A4E4EAAD7143749CD3740DF9BB95F"</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <h3 id="cons">Cons</h3> <ul> <li>It’s hard to understand those logs. Some additional analyzers might be needed.</li> <li>We don’t see request body here.</li> </ul> <h2 id="whats-next">What’s next?</h2> <p>Next time we will try other ways to get browser logs - including http statuses and request bodies.</p> <p><br /> <a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2019/12/16/advent-calendar-browser-logs/ https://selenide.org/2019/12/16/advent-calendar-browser-logs 2019-12-16T00:00:00+00:00 Drag and Drop <p>Hi all!</p> <p>Today is 15th day of our Selenide Advent Calendar.</p> <p>Today we will watch a short funny video demonstrating how to drag-and-drop elements in Selenide.</p> <h3 id="selenide-can-drag-and-drop-web-elements">Selenide can drag-and-drop web elements?</h3> <p>Yes, Selenide has method Drag’n’Drop. This is a boring description from Selenide blog:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"#from"</span><span class="o">).</span><span class="na">dragAndDropTo</span><span class="o">(</span><span class="s">"#to"</span><span class="o">)</span> </code></pre></div></div> <p>And this is a funny demonstration by Martin Škarbala:</p> <iframe width="800" height="490" src="https://www.youtube.com/embed/OSnwiosrMq0" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe> <p>That’s marvellous!</p> <p><br /> <a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2019/12/15/advent-calendar-drag-and-drop/ https://selenide.org/2019/12/15/advent-calendar-drag-and-drop 2019-12-15T00:00:00+00:00 Actions <p>Hi!</p> <p>In today’s advent calendar article we will check how to perform special operations in Selenide.</p> <p>Sometimes in our tests we encounter weird problems. It is 100% sure that all of us have experienced, or will experience some unusual problem that will make our work blocked. It happens quite often that for example we cannot click some element on the page, and standard selenium/selenide command 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="na">click</span><span class="o">();</span> </code></pre></div></div> <p>does not work. There can be many different reasons that will make our click operation ineffective but we cannot give up just like that, and we have to find some solution. In this case, in Selenium we had <code class="language-plaintext highlighter-rouge">Actions</code> class that helped us performing click operation in a bit different way:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">WebElement</span> <span class="n">element</span> <span class="o">=</span> <span class="o">&lt;</span><span class="nc">Some</span> <span class="n">selector</span><span class="o">&gt;;</span> <span class="nc">Actions</span> <span class="n">actions</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Actions</span><span class="o">(</span><span class="n">driver</span><span class="o">);</span> <span class="n">actions</span><span class="o">.</span><span class="na">moveToElement</span><span class="o">(</span><span class="n">element</span><span class="o">);</span> <span class="n">actions</span><span class="o">.</span><span class="na">click</span><span class="o">();</span> <span class="n">actions</span><span class="o">.</span><span class="na">build</span><span class="o">().</span><span class="na">perform</span><span class="o">();</span> </code></pre></div></div> <p>This way we were able to click the element and solve some of our problems occurring in tests.</p> <h4 id="but-how-can-we-do-it-in-selenide">But how can we do it in Selenide?</h4> <p>As it turns out, it is easier and simpler than it was in Selenium.<br /> Selenide solves many problems that were quite common in Selenium, but if we need to perform some things in a bit different way, actions are still available in Selenide. Here we can check how it goes:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">SelenideElement</span> <span class="n">element</span> <span class="o">=</span> <span class="err">$</span><span class="o">(&lt;</span><span class="n">some</span> <span class="n">selector</span><span class="o">&gt;);</span> <span class="n">actions</span><span class="o">().</span><span class="na">moveToElement</span><span class="o">(</span><span class="n">element</span><span class="o">).</span><span class="na">click</span><span class="o">(</span><span class="n">element</span><span class="o">).</span><span class="na">perform</span><span class="o">();</span> </code></pre></div></div> <p>As we can see, <code class="language-plaintext highlighter-rouge">actions</code> is just a method available when we have:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">Selenide</span><span class="o">.*;</span> </code></pre></div></div> <p>imported to our project. Notice that no driver is needed to use <code class="language-plaintext highlighter-rouge">actions()</code> method!</p> <h5 id="crazy-drag-and-drop">Crazy drag and drop</h5> <p>If you have read the documentation, you probably already know that there are two types of drag and drop operations available in Selenide by default:</p> <ol> <li><code class="language-plaintext highlighter-rouge">dragAndDropTo​(java.lang.String targetCssSelector);</code></li> <li><code class="language-plaintext highlighter-rouge">dragAndDropTo​(org.openqa.selenium.WebElement target);</code></li> </ol> <p>First method will let us drag and drop element to CSS selector defining target element.<br /> Second method will just let us drag and drop some element to another one.</p> <p>But what if we want to perform drag and drop action and we have no target element or css selector available?<br /> For example, we have just an empty page and we want to put there some objects in many different places.<br /> In this case, actions method will help us again. In Selenium we would have to code something like this:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">WebElement</span> <span class="n">element</span> <span class="o">=</span> <span class="n">driver</span><span class="o">.</span><span class="na">findElement</span><span class="o">(</span><span class="nc">By</span><span class="o">.</span><span class="na">some</span><span class="o">);</span> <span class="nc">Actions</span> <span class="n">actions</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Actions</span><span class="o">(</span><span class="n">driver</span><span class="o">);</span> <span class="n">actions</span><span class="o">.</span><span class="na">dragAndDropBy</span><span class="o">(</span><span class="n">element</span><span class="o">,</span> <span class="n">xOffset</span><span class="o">,</span> <span class="n">yOffset</span><span class="o">).</span><span class="na">perform</span><span class="o">();</span> </code></pre></div></div> <p>Where <code class="language-plaintext highlighter-rouge">xOffset</code> is a horizontal move offset and <code class="language-plaintext highlighter-rouge">yOffset</code> is a vertical move offset.</p> <p>In Selenide it should look like this:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">SelenideElement</span> <span class="n">element</span> <span class="o">=</span> <span class="o">&lt;</span><span class="nc">Some</span> <span class="n">selector</span><span class="o">&gt;;</span> <span class="n">actions</span><span class="o">().</span><span class="na">dragAndDropBy</span><span class="o">(</span><span class="n">element</span><span class="o">,</span> <span class="n">xOffset</span><span class="o">,</span> <span class="n">yOffset</span><span class="o">).</span><span class="na">perform</span><span class="o">();</span> </code></pre></div></div> <p>This way we can drag and drop some object to the desired location without using additional target identifiers.</p> <h2 id="whats-next">What’s next</h2> <p>Of course, these are just two examples of using special methods in Selenide and user can experiment with many more options.</p> <p>Enjoy actions() !</p> <p>Maciej Grymuza (figrym@gmail.com)</p> https://selenide.org/2019/12/12/advent-calendar-actions/ https://selenide.org/2019/12/12/advent-calendar-actions 2019-12-12T00:00:00+00:00 How to download a file with Selenide <p>Good evening!<br /> Today is December - and in this Selenide Advent calendar article we will take a look at the file download options in Selenide.</p> <p><strong>UPD</strong><br /> This article describes only 2 methods for downloading a file: <a href="#HTTPGET"><code class="language-plaintext highlighter-rouge">HTTPGET</code></a> and <a href="#PROXY"><code class="language-plaintext highlighter-rouge">PROXY</code></a>. Later we added <a href="/2020/07/08/selenide-5.13.0/#new-file-download-mode-folder">the third method <code class="language-plaintext highlighter-rouge">FOLDER</code></a> and <a href="/2024/02/07/selenide-7.1.0/#download-files-with-cdp">the fourth method <code class="language-plaintext highlighter-rouge">CDP</code></a>. Probably you need one of these methods - if your link doesn’t have <code class="language-plaintext highlighter-rouge">href</code> attribute, and you cannot enable proxy for some reason.</p> <p><br /></p> <h1 id="how-can-i-download-some-file-in-my-test">How can I download some file in my test?</h1> <p>At some point of our career all of us will face the problem of downloading the file in the test.</p> <p>As we remember, in Selenium it wasn’t that easy, because different browsers required different configurations like creating new user profile in Firefox and setting preferences:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">profile</span><span class="o">.</span><span class="na">setPreference</span><span class="o">(</span><span class="s">"browser.download.dir"</span><span class="o">,</span> <span class="n">downloadPath</span><span class="o">);</span> <span class="n">profile</span><span class="o">.</span><span class="na">setPreference</span><span class="o">(</span><span class="s">"browser.download.folderList"</span><span class="o">,</span> <span class="mi">2</span><span class="o">);</span> <span class="n">profile</span><span class="o">.</span><span class="na">setPreference</span><span class="o">(</span><span class="s">"browser.download.manager.showWhenStarting"</span><span class="o">,</span> <span class="kc">false</span><span class="o">);</span> <span class="n">profile</span><span class="o">.</span><span class="na">setPreference</span><span class="o">(</span><span class="s">"browser.helperApps.alwaysAsk.force"</span><span class="o">,</span> <span class="kc">false</span><span class="o">);</span> <span class="n">profile</span><span class="o">.</span><span class="na">setPreference</span><span class="o">(</span><span class="s">"browser.helperApps.neverAsk.saveToDisk"</span><span class="o">,</span> <span class="n">mimeTypes</span><span class="o">);</span> <span class="n">profile</span><span class="o">.</span><span class="na">setPreference</span><span class="o">(</span><span class="s">"browser.download.manager.focusWhenStarting"</span><span class="o">,</span><span class="kc">false</span><span class="o">);</span> <span class="n">profile</span><span class="o">.</span><span class="na">setPreference</span><span class="o">(</span><span class="s">"browser.download.manager.useWindow"</span><span class="o">,</span> <span class="kc">false</span><span class="o">);</span> <span class="n">profile</span><span class="o">.</span><span class="na">setPreference</span><span class="o">(</span><span class="s">"browser.download.manager.showAlertOnComplete"</span><span class="o">,</span> <span class="kc">false</span><span class="o">);</span> <span class="n">profile</span><span class="o">.</span><span class="na">setPreference</span><span class="o">(</span><span class="s">"pdfjs.disabled"</span><span class="o">,</span> <span class="kc">true</span><span class="o">);</span> </code></pre></div></div> <h3 id="HTTPGET">In Selenide,</h3> <p>this problem has been solved by adding <code class="language-plaintext highlighter-rouge">$.download()</code> method.</p> <p>When we want to download some file, we just have to perform:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">File</span> <span class="n">report</span> <span class="o">=</span> <span class="n">element</span><span class="o">.</span><span class="na">download</span><span class="o">();</span> </code></pre></div></div> <p>and Selenide will handle with all downloads window popup and just close them when process is finished.</p> <p>Selenide will create new folder containing our file in <code class="language-plaintext highlighter-rouge">build/reports/tests</code>. This is the folder where Gradle generate its rest reports, so that it’s convenient to have them all together.</p> <p>We can edit our download directory by changing default 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">downloadsFolder</span> <span class="o">=</span> <span class="o">&lt;</span><span class="n">desired</span> <span class="n">location</span> <span class="k">for</span> <span class="n">downloaded</span> <span class="n">files</span><span class="o">&gt;;</span> </code></pre></div></div> <h3 id="PROXY">BUT:</h3> <p>This way we will be able to download some file only when its element has “href” attribute.</p> <p>What if my element does not have “href” attribute? For example, if file is generated as a result of form submission.</p> <p>In this case, we have to organize downloading of our files in a bit different way. First of all we have to change 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">proxyEnabled</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span> <span class="nc">Configuration</span><span class="o">.</span><span class="na">fileDownload</span> <span class="o">=</span> <span class="no">PROXY</span><span class="o">;</span> </code></pre></div></div> <p>After changing these settings, we are able to download files from all kinds of elements, we don’t need a <code class="language-plaintext highlighter-rouge">href</code> attribute anymore - and we just have to use:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">File</span> <span class="n">report</span> <span class="o">=</span> <span class="n">element</span><span class="o">.</span><span class="na">download</span><span class="o">();</span> </code></pre></div></div> <h3 id="tip">Tip:</h3> <p>Remember to set the appropriate timeout if you want to download files that have a big size - it will take more time to download them.</p> <p>File will be downloaded to the default folder (something like <code class="language-plaintext highlighter-rouge">C:\downloads and settings\downloads</code>).<br /> We have to remember that in case of some browsers, files are also downloaded to system downloads folder so our file will be present in two locations.</p> <p>In the next steps we can for example delete folder with downloaded file using:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">FileUtils</span><span class="o">.</span><span class="na">deleteDirectory</span><span class="o">(</span><span class="k">new</span> <span class="nc">File</span><span class="o">(&lt;</span><span class="n">folder</span> <span class="n">we</span> <span class="n">want</span> <span class="n">to</span> <span class="n">delete</span><span class="o">&gt;));</span> </code></pre></div></div> <p>For more detailed info about file downloading mechanism read <a href="https://selenide.org/2016/08/27/selenide-3.9.1/">this post</a>.</p> <p>Maciej Grymuza (figrym@gmail.com)</p> https://selenide.org/2019/12/10/advent-calendar-download-files/ https://selenide.org/2019/12/10/advent-calendar-download-files 2019-12-10T00:00:00+00:00 Why we banned statics and then allowed again? <p>Good evening!</p> <p>Here is the 9th day of Selenide Advent Calendar, and<br /> I’ll tell you what excites the public most of all.</p> <h1 id="why-statics-were-banned-in-selenide-500-but-allowed-again-in-540">Why statics were banned in Selenide 5.0.0, but allowed again in 5.4.0?</h1> <p>Short answer: we banned them occasionally. But it was good.</p> <p>Let me explain it in detail :)</p> <h3 id="how-selenide-holds-webdrivers">How Selenide holds WebDrivers</h3> <p>Selenide stores webdriver instances in ThreadLocal.<br /> It allows you to run tests in parallel: different threads get different webdrivers. The code looks like this:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">WebDriverRunner</span> <span class="o">{</span> <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">ThreadLocal</span><span class="o">&lt;</span><span class="nc">WebDriver</span><span class="o">&gt;</span> <span class="n">webdriver</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ThreadLocal</span><span class="o">&lt;&gt;();</span> <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">ThreadLocal</span><span class="o">&lt;</span><span class="nc">SelenideProxyServer</span><span class="o">&gt;</span> <span class="n">proxy</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ThreadLocal</span><span class="o">&lt;&gt;();</span> <span class="o">}</span> </code></pre></div></div> <p>Say, method <code class="language-plaintext highlighter-rouge">$("a").click()</code> works like this:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">WebDriverRunner</span><span class="o">.</span><span class="na">webdriver</span><span class="o">.</span><span class="na">get</span><span class="o">().</span><span class="na">findElement</span><span class="o">(</span><span class="s">"a"</span><span class="o">).</span><span class="na">click</span><span class="o">();</span> </code></pre></div></div> <h2 id="briefly-about-selenidedriver">Briefly about SelenideDriver</h2> <p>But ThreadLocal implies one limitation: you cannot use two webdrivers in one thread<br /> (as well as one webdriver in two threads - but aren’t there yet).</p> <p>We planned to solve this problem in Selenide 5.0.0. We created a special class <code class="language-plaintext highlighter-rouge">SelenideDriver</code>, that allowed you to use two webdrivers in one test:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">SelenideDriver</span> <span class="n">browser1</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">SelenideDriver</span><span class="o">();</span> <span class="nc">SelenideDriver</span> <span class="n">browser2</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">SelenideDriver</span><span class="o">();</span> <span class="n">browser1</span><span class="o">.</span><span class="na">open</span><span class="o">(</span><span class="s">"https://google.com"</span><span class="o">);</span> <span class="n">browser2</span><span class="o">.</span><span class="na">open</span><span class="o">(</span><span class="s">"http://yandex.ru"</span><span class="o">);</span> <span class="n">browser1</span><span class="o">.</span><span class="err">$</span><span class="o">(</span><span class="n">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">"Google"</span><span class="o">));</span> <span class="n">browser2</span><span class="o">.</span><span class="err">$</span><span class="o">(</span><span class="n">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">"Yandeks"</span><span class="o">));</span> </code></pre></div></div> <p>It forces us to do a major refactoring: we removed all usages of old good static method <code class="language-plaintext highlighter-rouge">open()</code>, <code class="language-plaintext highlighter-rouge">$</code> and <code class="language-plaintext highlighter-rouge">$$</code> inside Selenide itself. Every piece of Selenide code that needs a webdriver now gets a <code class="language-plaintext highlighter-rouge">SelenideDriver</code> parameter.<br /> Yes, we had to pass this parameter everywhere…</p> <h2 id="here-comes-the-question">Here comes the question</h2> <p>What should we do with old good static methods <code class="language-plaintext highlighter-rouge">open()</code>, <code class="language-plaintext highlighter-rouge">$</code> and <code class="language-plaintext highlighter-rouge">$$</code>? They have to get <code class="language-plaintext highlighter-rouge">SelenideDriver</code> instance somewhere. Where to take it from?</p> <h2 id="selenide-500-statics-got-a-punch">Selenide 5.0.0: Statics got a punch</h2> <p>We added to class <code class="language-plaintext highlighter-rouge">WebDriverRunner</code> a third ThreadLocal:</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">ThreadLocal</span><span class="o">&lt;</span><span class="nc">SelenideDriver</span><span class="o">&gt;</span> <span class="n">selenideDriver</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ThreadLocal</span><span class="o">&lt;&gt;();</span> </code></pre></div></div> <p>Briefly, <code class="language-plaintext highlighter-rouge">SelenideDriver</code> is a simple class with two fields <code class="language-plaintext highlighter-rouge">WebDriver</code> and <code class="language-plaintext highlighter-rouge">SelenideProxyServer</code>.<br /> In general, it worked and solved the initial problem.</p> <p>What I could not have envisioned at that moment was that so many folks defined their web elements in static fields:</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">MyPageObject</span> <span class="o">{</span> <span class="kd">public</span> <span class="kd">static</span> <span class="nc">SelenideElement</span> <span class="n">fname</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#fname"</span><span class="o">);</span> <span class="kd">public</span> <span class="kd">static</span> <span class="nc">SelenideElement</span> <span class="n">lname</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#lname"</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>And re-open the webdriver between tests.</p> <h3 id="one-important-detail">One important detail:</h3> <p>We did one more improvement in Selenide 5.0.0.</p> <p>Before 5.0.0, Selenide automatically opened a new browser if it wasn’t opened yet. At any moment. <br /> Sometimes it caused perplexity because browser opened at unexpected moments (for example, when trying to log an error caused by a crashed browser).</p> <p>Of course, it happened because of bad tests. Bug after all, <em>we created Selenide to help people, right?</em></p> <p>That’s why starting from version 5.0.0, Selenide didn’t occasionally open a browser anymore.<br /> Instead, it said: “There is no an opened browser, I cannot do my job. You need to call method <code class="language-plaintext highlighter-rouge">open()</code> first.”</p> <h3 id="and-what-failed-then">And what failed then?</h3> <p>The coincidence of these two factors led to the following problem:</p> <ol> <li>Test creates a static field <code class="language-plaintext highlighter-rouge">static SelenideElement fname = $("#fname")</code>.</li> <li>This <code class="language-plaintext highlighter-rouge">fname</code> remembers a <code class="language-plaintext highlighter-rouge">SelenideDriver</code> it was created with.</li> <li>Test closes the browser in the end.</li> <li>A following test opens a new browser tries to use static field <code class="language-plaintext highlighter-rouge">fname</code>.</li> <li>And <code class="language-plaintext highlighter-rouge">fname</code> calls its own instance of <code class="language-plaintext highlighter-rouge">SelenideDriver</code> it was created with.</li> <li>And fails, because <em>that</em> `SelenideDriver has been closed.</li> </ol> <p>More than a year - from September, 2018 to October, 2019 - I was trying to explain that static variables are evil.<br /> I even created a special talk <a href="https://www.youtube.com/watch?v=dFQSOlOOoXE&amp;list=PLfazdZ9SzB9eDJIugtfH7KeVLLAP1pDLh">“Antistatic”</a> (yes, this time in English:)).</p> <p>But finally I gave up. Because it would be too big refactoring for many folks to rewrite their projects from static variables.</p> <p>After all, <em>we created Selenide to help people, right?</em></p> <h2 id="selenide-540-statics-won">Selenide 5.4.0: Statics won</h2> <p>How we finally solved this problem?</p> <p>The solution is quite simple. We replaced <code class="language-plaintext highlighter-rouge">ThreadLocal&lt;SelenideDriver&gt;</code> by a static variable (yep :))</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">SelenideDriver</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ThreadLocalSelenideDriver</span><span class="o">();</span> </code></pre></div></div> <p>Now this “static” <code class="language-plaintext highlighter-rouge">SelenideDriver</code> is a singleton. It always exists. It’s never closed. All static <code class="language-plaintext highlighter-rouge">SelenideElement</code> variables created with it will live forever. But it also doesn’t hold fields <code class="language-plaintext highlighter-rouge">WebDriver</code> and <code class="language-plaintext highlighter-rouge">SelenideProxyServer</code>. It fetches them from <code class="language-plaintext highlighter-rouge">WebDriverRunner</code>’s ThreadLocals every time.</p> <h3 id="ps">P.S.</h3> <p>That’s why method <code class="language-plaintext highlighter-rouge">WebDriverRunner.getSelenideDriver()</code> disappeared in Selenide 5.4.0.</p> <p>I was surprised that many people have already managed to use it. People, I do not understand you! <em>How do you manage to use everything so wrong?</em><br /> Well, it was my mistake to make this method public. But I never mentioned it in any of my posts nor documentation. I never recommended to use. How could someone decide to use it? How this magic happens?</p> <h2 id="whats-now">What’s now</h2> <p>We returned the possibility to declare your <code class="language-plaintext highlighter-rouge">SelenideElement</code>s in static fields.</p> <p>But please do not abuse it.</p> <p>I still don’t like it :)</p> <p><br /> <a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2019/12/09/advent-calendar-statics/ https://selenide.org/2019/12/09/advent-calendar-statics 2019-12-09T00:00:00+00:00 How to test CSRF protection <p>Hi all!</p> <p>Today is 7th day of our Selenide Advent Calendar. <br /> Today we will talk about testing security.</p> <h1 id="what-is-csrf">What is CSRF?</h1> <p><a href="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)">CSRF</a> is one of the most popular security attacks (Cross-Site Request Forgery).</p> <p>To protect itself from CSRF attack, a web-application should add a special parameter to (almost) every POST request. Typically it’s called <code class="language-plaintext highlighter-rouge">authenticityToken</code> (though the name may vary).</p> <p>A typical mistake is when web-application either doesn’t send <code class="language-plaintext highlighter-rouge">authenticityToken</code> to server with some POST request or doesn’t check it on server side.</p> <h3 id="how-to-check-the-protection">How to check the protection?</h3> <p>I assume you have some automated tests covering the most critical functionality of your web application.<br /> We will kill two birds with one stone: during run of your tests, we will intercept every POST request and send exactly the same request, but with modified <code class="language-plaintext highlighter-rouge">authenticityToken</code>. And verify that the server returned an error. Usually it should be “403 Forbidden”.</p> <h3 id="sounds-hard-how-to-program-it">Sounds hard. How to program it?</h3> <p>Now so hard.<br /> As you know, Selenide can run its own embedded proxy server. Initially it was created for downloading files, but it also allows to add your own listeners which can intercept all requests between browser and server. We are going to use it.</p> <p><br /> <br /></p> <h4 id="step-1-enable-selenide-proxy">Step 1. Enable Selenide proxy</h4> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Configuration</span><span class="o">.</span><span class="na">proxyEnabled</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span> </code></pre></div></div> <p>(you need to do it BEFORE opening a browser)</p> <p><br /> <br /></p> <h4 id="step-2-add-listener-for-the-proxy">Step 2. Add listener for the proxy</h4> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">abstract</span> <span class="kd">class</span> <span class="nc">BaseTest</span> <span class="o">{</span> <span class="kd">private</span> <span class="nc">AuthenticityTokenChecker</span> <span class="n">authenticityTokenChecker</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">AuthenticityTokenChecker</span><span class="o">();</span> <span class="c1">// somewhere after open("http://..."):</span> <span class="n">getSelenideProxy</span><span class="o">().</span><span class="na">getProxy</span><span class="o">().</span><span class="na">addRequestFilter</span><span class="o">(</span><span class="n">authenticityTokenChecker</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>Currently you can only add listeners AFTER opening a browser, which is sometimes inconvenient. I hope we will implement adding listeners at any moment in next Selenide release.</p> <p><br /></p> <h4 id="step-3-implement-authenticitytokenchecker">Step 3. Implement AuthenticityTokenChecker</h4> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">com.codeborne.selenide.Configuration</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">io.netty.handler.codec.http.*</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">net.lightbody.bmp.filters.*</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">net.lightbody.bmp.util.*</span><span class="o">;</span> <span class="kd">public</span> <span class="kd">class</span> <span class="nc">AuthenticityTokenChecker</span> <span class="kd">implements</span> <span class="nc">RequestFilter</span> <span class="o">{</span> <span class="kd">private</span> <span class="kd">final</span> <span class="nc">HttpClient</span> <span class="n">httpClient</span> <span class="o">=</span> <span class="nc">HttpClient</span><span class="o">.</span><span class="na">newBuilder</span><span class="o">().</span><span class="na">build</span><span class="o">();</span> <span class="kd">private</span> <span class="kd">final</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="n">unprotectedUrls</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;(</span><span class="mi">1</span><span class="o">);</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">reset</span><span class="o">()</span> <span class="o">{</span> <span class="n">unprotectedUrls</span><span class="o">.</span><span class="na">clear</span><span class="o">();</span> <span class="o">}</span> <span class="kd">public</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="nf">getUnprotectedUrls</span><span class="o">()</span> <span class="o">{</span> <span class="k">return</span> <span class="n">unprotectedUrls</span><span class="o">;</span> <span class="o">}</span> <span class="nd">@Override</span> <span class="kd">public</span> <span class="nc">HttpResponse</span> <span class="nf">filterRequest</span><span class="o">(</span><span class="nc">HttpRequest</span> <span class="n">httpRequest</span><span class="o">,</span> <span class="nc">HttpMessageContents</span> <span class="n">contents</span><span class="o">,</span> <span class="nc">HttpMessageInfo</span> <span class="n">httpMessageInfo</span><span class="o">)</span> <span class="o">{</span> <span class="k">if</span> <span class="o">(</span><span class="n">httpRequest</span><span class="o">.</span><span class="na">getMethod</span><span class="o">()</span> <span class="o">!=</span> <span class="nc">HttpMethod</span><span class="o">.</span><span class="na">POST</span><span class="o">)</span> <span class="k">return</span> <span class="kc">null</span><span class="o">;</span> <span class="c1">// ignore non-POST requests</span> <span class="k">if</span> <span class="o">(!</span><span class="n">httpRequest</span><span class="o">.</span><span class="na">getUri</span><span class="o">().</span><span class="na">startsWith</span><span class="o">(</span><span class="nc">Configuration</span><span class="o">.</span><span class="na">baseUrl</span><span class="o">))</span> <span class="k">return</span> <span class="kc">null</span><span class="o">;</span> <span class="c1">// ignore chrome requests to google.com etc.</span> <span class="k">if</span> <span class="o">(</span><span class="k">this</span> <span class="n">url</span> <span class="n">can</span> <span class="n">work</span> <span class="n">without</span> <span class="n">authenticityToken</span><span class="o">)</span> <span class="k">return</span> <span class="kc">null</span><span class="o">;</span> <span class="c1">// some post requests don't need csrf protection</span> <span class="nc">String</span> <span class="n">body</span> <span class="o">=</span> <span class="n">contents</span><span class="o">.</span><span class="na">getTextContents</span><span class="o">();</span> <span class="k">if</span> <span class="o">(!</span><span class="n">body</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="s">"authenticityToken="</span><span class="o">))</span> <span class="o">{</span> <span class="n">unprotectedUrls</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="s">"No 'authenticityToken=' found for "</span> <span class="o">+</span> <span class="n">httpRequest</span><span class="o">.</span><span class="na">getUri</span><span class="o">()</span> <span class="o">+</span> <span class="s">" in "</span> <span class="o">+</span> <span class="n">body</span><span class="o">);</span> <span class="k">return</span> <span class="kc">null</span><span class="o">;</span> <span class="o">}</span> <span class="n">sendHackedPostRequest</span><span class="o">(</span><span class="n">httpRequest</span><span class="o">,</span> <span class="n">contents</span><span class="o">);</span> <span class="k">return</span> <span class="kc">null</span><span class="o">;</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div></div> <p>Note that <code class="language-plaintext highlighter-rouge">return null;</code> means “do not modify the request”, which means that the browser will still send the original request, and the normal flow of your test will not be affected.</p> <p><br /></p> <h4 id="step-4-send-hacked-post-request">Step 4. Send hacked POST request</h4> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">private</span> <span class="kt">void</span> <span class="nf">sendHackedPostRequest</span><span class="o">(</span><span class="nc">HttpRequest</span> <span class="n">httpRequest</span><span class="o">,</span> <span class="nc">HttpMessageContents</span> <span class="n">contents</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">IOException</span><span class="o">,</span> <span class="nc">InterruptedException</span> <span class="o">{</span> <span class="c1">// You need to tune this line. </span> <span class="c1">// The request format (including name of parameter "authenticityToken") may depend on your application.</span> <span class="c1">// Note that the request can contain several "authenticityToken" parameters (immediately throw an error if they are different).</span> <span class="c1">// If the request contains a submitted form, especially with uploaded files, you need to modify "authenticityToken" a little bit differently. </span> <span class="nc">String</span> <span class="n">hackedBody</span> <span class="o">=</span> <span class="n">contents</span><span class="o">.</span><span class="na">getTextContents</span><span class="o">()</span> <span class="o">.</span><span class="na">replace</span><span class="o">(</span><span class="s">"authenticityToken=1234567890"</span><span class="o">).</span><span class="na">to</span><span class="o">(</span><span class="s">"authenticityToken=hack-me-if-you-can"</span><span class="o">);</span> <span class="n">java</span><span class="o">.</span><span class="na">net</span><span class="o">.</span><span class="na">http</span><span class="o">.</span><span class="na">HttpRequest</span><span class="o">.</span><span class="na">Builder</span> <span class="n">builder</span> <span class="o">=</span> <span class="n">java</span><span class="o">.</span><span class="na">net</span><span class="o">.</span><span class="na">http</span><span class="o">.</span><span class="na">HttpRequest</span><span class="o">.</span><span class="na">newBuilder</span><span class="o">()</span> <span class="o">.</span><span class="na">uri</span><span class="o">(</span><span class="no">URI</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="n">httpRequest</span><span class="o">.</span><span class="na">getUri</span><span class="o">()))</span> <span class="o">.</span><span class="na">timeout</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">1</span><span class="o">));</span> <span class="k">for</span> <span class="o">(</span><span class="nc">Map</span><span class="o">.</span><span class="na">Entry</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">String</span><span class="o">&gt;</span> <span class="n">header</span> <span class="o">:</span> <span class="n">httpRequest</span><span class="o">.</span><span class="na">headers</span><span class="o">())</span> <span class="o">{</span> <span class="k">if</span> <span class="o">(!</span><span class="n">restrictedHeaders</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="n">header</span><span class="o">.</span><span class="na">getKey</span><span class="o">().</span><span class="na">toLowerCase</span><span class="o">()))</span> <span class="o">{</span> <span class="n">builder</span><span class="o">.</span><span class="na">header</span><span class="o">(</span><span class="n">header</span><span class="o">.</span><span class="na">getKey</span><span class="o">(),</span> <span class="n">header</span><span class="o">.</span><span class="na">getValue</span><span class="o">());</span> <span class="o">}</span> <span class="o">}</span> <span class="n">java</span><span class="o">.</span><span class="na">net</span><span class="o">.</span><span class="na">http</span><span class="o">.</span><span class="na">HttpRequest</span> <span class="n">request</span> <span class="o">=</span> <span class="n">builder</span> <span class="o">.</span><span class="na">POST</span><span class="o">(</span><span class="n">java</span><span class="o">.</span><span class="na">net</span><span class="o">.</span><span class="na">http</span><span class="o">.</span><span class="na">HttpRequest</span><span class="o">.</span><span class="na">BodyPublishers</span><span class="o">.</span><span class="na">ofString</span><span class="o">(</span><span class="n">hackedBody</span><span class="o">))</span> <span class="o">.</span><span class="na">build</span><span class="o">();</span> <span class="n">log</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"Sending hacked request to {}"</span><span class="o">,</span> <span class="n">httpRequest</span><span class="o">.</span><span class="na">getUri</span><span class="o">());</span> <span class="n">java</span><span class="o">.</span><span class="na">net</span><span class="o">.</span><span class="na">http</span><span class="o">.</span><span class="na">HttpResponse</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="n">httpResponse</span> <span class="o">=</span> <span class="n">httpClient</span><span class="o">.</span><span class="na">send</span><span class="o">(</span><span class="n">request</span><span class="o">,</span> <span class="n">java</span><span class="o">.</span><span class="na">net</span><span class="o">.</span><span class="na">http</span><span class="o">.</span><span class="na">HttpResponse</span><span class="o">.</span><span class="na">BodyHandlers</span><span class="o">.</span><span class="na">ofString</span><span class="o">());</span> <span class="k">if</span> <span class="o">(</span><span class="n">httpResponse</span><span class="o">.</span><span class="na">statusCode</span><span class="o">()</span> <span class="o">==</span> <span class="mi">403</span><span class="o">)</span> <span class="o">{</span> <span class="n">log</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"Hacked request was rejected: {} {}"</span><span class="o">,</span> <span class="n">httpResponse</span><span class="o">.</span><span class="na">statusCode</span><span class="o">(),</span> <span class="n">httpRequest</span><span class="o">.</span><span class="na">getUri</span><span class="o">());</span> <span class="o">}</span> <span class="k">else</span> <span class="o">{</span> <span class="n">log</span><span class="o">.</span><span class="na">error</span><span class="o">(</span><span class="s">"HACK SUCCEEDED {} {}"</span><span class="o">,</span> <span class="n">httpResponse</span><span class="o">.</span><span class="na">statusCode</span><span class="o">(),</span> <span class="n">httpRequest</span><span class="o">.</span><span class="na">getUri</span><span class="o">());</span> <span class="n">unprotectedUrls</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="s">"Detected URL without authenticity token check: "</span> <span class="o">+</span> <span class="n">httpRequest</span><span class="o">.</span><span class="na">getUri</span><span class="o">());</span> <span class="o">}</span> <span class="o">}</span> <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">Set</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="n">restrictedHeaders</span> <span class="o">=</span> <span class="nc">Set</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="s">"connection"</span><span class="o">,</span> <span class="s">"content-length"</span><span class="o">,</span> <span class="s">"date"</span><span class="o">,</span> <span class="s">"expect"</span><span class="o">,</span> <span class="s">"from"</span><span class="o">,</span> <span class="s">"host"</span><span class="o">,</span> <span class="s">"upgrade"</span><span class="o">,</span> <span class="s">"via"</span><span class="o">,</span> <span class="s">"warning"</span><span class="o">);</span> </code></pre></div></div> <p>This implementation uses Java 11 built-in <code class="language-plaintext highlighter-rouge">HttpClient</code>. If you are that poor guy that still uses Java 8, you can easily replace it with OkHttp, Apache Http Client or some similar http client.</p> <p><br /></p> <h4 id="step-5-fail-the-test-if-some-hacked-request-hasnt-got-forbidden-error">Step 5. Fail the test if some hacked request hasn’t got “Forbidden” error</h4> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">abstract</span> <span class="kd">class</span> <span class="nc">BaseTest</span> <span class="o">{</span> <span class="nd">@Before</span> <span class="kt">void</span> <span class="nf">resetChecker</span><span class="o">()</span> <span class="o">{</span> <span class="n">authenticityTokenChecker</span><span class="o">.</span><span class="na">reset</span><span class="o">();</span> <span class="o">}</span> <span class="nd">@After</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">verifyThatAllPostRequestsAreProtectedWithAuthenticityToken</span><span class="o">()</span> <span class="o">{</span> <span class="k">if</span> <span class="o">(!</span><span class="n">authenticityTokenChecker</span><span class="o">.</span><span class="na">getUnprotectedUrls</span><span class="o">().</span><span class="na">isEmpty</span><span class="o">())</span> <span class="o">{</span> <span class="n">fail</span><span class="o">(</span><span class="nc">String</span><span class="o">.</span><span class="na">valueOf</span><span class="o">(</span><span class="n">authenticityTokenChecker</span><span class="o">.</span><span class="na">getUnprotectedUrls</span><span class="o">()));</span> <span class="o">}</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div></div> <p><br /></p> <h2 id="whats-now">What’s now?</h2> <p>We managed to automatically check if our application is protected against CSRF attacks.<br /> (It’s not theoretical: we actually did it in one project and found two vulnerabilities in a real internet-bank.)</p> <p>It’s good, but it’s not enough. There is a lot of other security attacks.</p> <p>Keep track of <a href="https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project">OWASP 10</a>, think creatively, and try to figure out how you could emulate other attacks with your automated tests.</p> <p><br /></p> <p><br /> <a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2019/12/07/advent-calendar-csrf-protection/ https://selenide.org/2019/12/07/advent-calendar-csrf-protection 2019-12-07T00:00:00+00:00 How to visualize click <p>Good evening!</p> <p>Today is December 6th, you are reading the Selenide Advent calendar, and in today’s post I will show one simple technique how to catch some flaky tests.</p> <h1 id="whats-wring-with-clicks">What’s wring with clicks?</h1> <p>It’s an eternal problem: flaky tests. One of typical reasons of flaky tests: click doesn’t work.</p> <p>As i described <a href="https://www.youtube.com/watch?v=ibx8nVvt-Js">in this video</a> on DelEx 2019 conference (sorry, the video is in Russian), click in selenium often doesn’t work if the element was moving or resizing at that moment. Or if it was covered by other element that suddenly appeared and got the click.</p> <h3 id="why-selenide-hasnt-solved-it-already">Why Selenide hasn’t solved it already?</h3> <p>A global solution could be like this: method <code class="language-plaintext highlighter-rouge">$.click()</code> waits for completion of any animations and movements before actually performing the click. Currently Selenide doesn’t have such a solution. I guess it’s impossible to make such waiting universal. All projects are different, with different frameworks and designs. If you have an idea how to implement such a waiting - feel free to drop me a notice.</p> <p>But what we can is to highlight the element that actually got the click. It will not solve the problem entirely, but at least it helps to localize the problem.</p> <h3 id="how-to-highlight-the-element">How to highlight the element?</h3> <p>You can add the following JS code to your application.<br /> It listens for all click events on the page and adds highlights with a green border the element that actually got the click.<br /> It will help you to detect cases where a wrong element got the click.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">#</span><span class="o">{</span><span class="k">if</span> <span class="n">test</span><span class="o">}</span> <span class="o">&lt;</span><span class="n">script</span><span class="o">&gt;</span> <span class="n">function</span> <span class="nf">onClick</span><span class="o">(</span><span class="n">event</span><span class="o">)</span> <span class="o">{</span> <span class="kt">var</span> <span class="n">e</span> <span class="o">=</span> <span class="n">event</span> <span class="o">||</span> <span class="n">window</span><span class="o">.</span><span class="na">event</span><span class="o">;</span> <span class="kt">var</span> <span class="n">target</span> <span class="o">=</span> <span class="n">e</span><span class="o">.</span><span class="na">target</span> <span class="o">||</span> <span class="n">e</span><span class="o">.</span><span class="na">srcElement</span><span class="o">;</span> <span class="n">target</span><span class="o">.</span><span class="na">style</span><span class="o">[</span><span class="err">'</span><span class="n">box</span><span class="o">-</span><span class="n">sizing</span><span class="err">'</span><span class="o">]</span> <span class="o">=</span> <span class="err">'</span><span class="n">border</span><span class="o">-</span><span class="n">box</span><span class="err">'</span><span class="o">;</span> <span class="n">target</span><span class="o">.</span><span class="na">style</span><span class="o">[</span><span class="err">'</span><span class="n">border</span><span class="err">'</span><span class="o">]</span> <span class="o">=</span> <span class="err">'</span><span class="mi">2</span><span class="n">px</span> <span class="n">solid</span> <span class="n">green</span><span class="err">'</span><span class="o">;</span> <span class="o">}</span> <span class="n">document</span><span class="o">.</span><span class="na">addEventListener</span><span class="o">(</span><span class="err">'</span><span class="n">click</span><span class="err">'</span><span class="o">,</span> <span class="n">onClick</span><span class="o">);</span> <span class="o">&lt;/</span><span class="n">script</span><span class="o">&gt;</span> <span class="err">#</span><span class="o">{/</span><span class="k">if</span><span class="o">}</span> </code></pre></div></div> <p>You might need to adjust this code to your needs: it depends on your application, framework, design etc.</p> <p>Here you can see one example of possible solutions: <a href="https://github.com/selenide-examples/gmail/blob/master/test/org/selenide/examples/gmail/Highlighter.java">Highlighter</a>.</p> <h2 id="whats-now">What’s now?</h2> <p>If you have flaky test (as all of us), you can start from this step.<br /> At least you will see which element got the click.</p> <p><br /></p> <p><br /> <a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2019/12/06/advent-calendar-visualize-click/ https://selenide.org/2019/12/06/advent-calendar-visualize-click 2019-12-06T00:00:00+00:00 How to check size effectively? <p>Hello!</p> <p>Today is December 4th, it’s the Selenide Advent calendar, and in today’s post I will show how to check a collection size effectively.</p> <h1 id="how-to-effectively-check-a-collection-size">How to effectively check a collection size?</h1> <p>Selenide has convenient methods for checking collections. For example, this is how you can check that a book list contains exactly 3 books:</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="err">$$</span><span class="o">(</span><span class="s">"#books .book"</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> <span class="o">}</span> </code></pre></div></div> <p>If this page implemented so that it contains much more books, and only some of them are visible, then you can filter the collection:</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="err">$$</span><span class="o">(</span><span class="s">"#books .book"</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">shouldHave</span><span class="o">(</span><span class="n">size</span><span class="o">(</span><span class="mi">3</span><span class="o">));</span> <span class="o">}</span> </code></pre></div></div> <h2 id="the-problem">The problem</h2> <p>If the page contains a lot of books (say, a few dozens or more), this filtration can be slow (say, few seconds and more).<br /> It’s because method <code class="language-plaintext highlighter-rouge">filter(visible)</code> needs to call <code class="language-plaintext highlighter-rouge">WebElement.isDisplayed()</code> separately for each element in the collection in loop. Every call means a separate call to webdriver, which is a separate http request etc. This all takes times.</p> <p>Probably tests run 3 days in your project, and few seconds don’t really play any role. Then you can skip this post. :)</p> <p>But if you care about effectiveness of your tests, go on.</p> <h2 id="the-first-try">The first try</h2> <p>How to speed up this check? The first idea is to filter elements right in the selector:</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="err">$$</span><span class="o">(</span><span class="s">"#books .book:visible"</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> <span class="o">}</span> </code></pre></div></div> <p>But this selector doesn’t work.</p> <p>The problem is that there is no CSS selector <code class="language-plaintext highlighter-rouge">:visible</code>. It doesn’t exist. Only JQuery can understand it.</p> <h2 id="the-second-try">The second try</h2> <p>Who saves us? Of course, JavaScript!</p> <p>You can create a helper method which finds a number of elements (with a help of JavaScript and JQuery):</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="kt">int</span> <span class="nf">sizeOf</span><span class="o">(</span><span class="nc">String</span> <span class="n">cssSelector</span><span class="o">)</span> <span class="o">{</span> <span class="nc">Number</span> <span class="n">count</span> <span class="o">=</span> <span class="n">executeJavaScript</span><span class="o">(</span><span class="s">"return $(arguments[0]).length"</span><span class="o">,</span> <span class="n">cssSelector</span><span class="o">);</span> <span class="k">return</span> <span class="n">count</span><span class="o">.</span><span class="na">intValue</span><span class="o">();</span> <span class="o">}</span> </code></pre></div></div> <p>(this code only works if the page contains JQuery library. If not, you can write a similar code using some other JavaScript library.)</p> <p>Now your check will be fast because it calls WebDriver method only once. And browser executes any JavaScript very quickly.</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">assertEquals</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="n">sizeOf</span><span class="o">(</span><span class="s">"#books .book:visible"</span><span class="o">));</span> <span class="o">}</span> </code></pre></div></div> <h2 id="whats-now">What’s now?</h2> <p>Learn the power of JavaScript. <br /> It allows many other tricks which can make your tests more fast and stable.</p> <p><br /></p> <p><br /> <a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2019/12/04/advent-calendar-effective-size-check/ https://selenide.org/2019/12/04/advent-calendar-effective-size-check 2019-12-04T00:00:00+00:00 setWebDriver or WebDriverProvider? <p>Good evening!</p> <p>Today is December 3rd, you are reading the Selenide Advent calendar, and in today’s post I will answer one simple question.</p> <h1 id="which-one-should-i-choose-setwebdriver-or-webdriverprovider">Which one should I choose, <code class="language-plaintext highlighter-rouge">setWebDriver()</code> or <code class="language-plaintext highlighter-rouge">WebDriverProvider</code>?</h1> <p>As you know, Selenide opens a browser automatically and closes it at the right moment. You don’t need to care about the browser.</p> <p>But sometimes you want to open a “custom” browser with some specific settings. Selenide has 2 methods for this. It happened so that I never wrote anywhere how to choose one of them.</p> <p>So,</p> <h4 id="option-1">Option 1:</h4> <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="nc">MyWebdriverProvider</span><span class="o">.</span><span class="na">class</span><span class="o">.</span><span class="na">getName</span><span class="o">();</span> </code></pre></div></div> <p>This option is preferred in most cases. It’s good because class <code class="language-plaintext highlighter-rouge">MyWebdriverProvider</code> is only responsible for HOW to open a browser (which options to pass, where to find binaries etc). But is not responsible for WHEN to open and close the browser. Selenide takes care of it.</p> <h4 id="option-2">Option 2:</h4> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Before</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setUp</span><span class="o">()</span> <span class="o">{</span> <span class="kt">var</span> <span class="n">yandexBrowser</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">YandexDriver</span><span class="o">(...);</span> <span class="nc">WebDriverRunner</span><span class="o">.</span><span class="na">setWebDriver</span><span class="o">(</span><span class="n">yandexBrowser</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>This option is worse because you are responsible not only for opening, but also for close the browser. This often causes misunderstanding. Selenide cannot close the browser because you might use it somewhere else. You open it - you close it.</p> <p>This begs the question:</p> <h3 id="why-its-needed-at-all">Why it’s needed at all?</h3> <p>Initially method <code class="language-plaintext highlighter-rouge">setWebDriver()</code> was created to enable easy adoption of Selenide in existing projects (without re-writing the existing codebase).</p> <p>Imagine that company X already has a lot of automated tests on Selenium (or HtmlElements, Thucydides, Serenity or anything else). They want to write new tests on Selenide, but leave existing tests untouched.</p> <p>Apparently they already have a code snippet in their codebase which opens and closes the browser. They want to say Selenide to use the same browser. That’s when method <code class="language-plaintext highlighter-rouge">setWebDriver()</code> is useful. It allows you to run the old and the new code all together, so that it works in the same browser.</p> <p>As you see, the use of method <code class="language-plaintext highlighter-rouge">setWebDriver()</code> is rather narrow. I’m not sure at all if it was ever used in that vein. :)</p> <h2 id="whats-now">What’s now?</h2> <p>If you are writing a new project, use <code class="language-plaintext highlighter-rouge">WebDriverProvider</code>. SRP.</p> <p><br /></p> <h1 id="driver-factory">UPD</h1> <p>Later in <a href="https://ru.selenide.org/2020/11/25/selenide-5.16.2/#selenide-5.16.2">Selenide 5.16.1</a> we added one more option <code class="language-plaintext highlighter-rouge">DriverFactory</code>. Now it’s the recommended way to create a customized webdriver.</p> <p>The idea is very similar to <code class="language-plaintext highlighter-rouge">WebDriverProvider</code>, but gives you more control over webdriver options. You need to</p> <ol> <li>either implement interface <code class="language-plaintext highlighter-rouge">DriverFactory</code>,</li> <li>or create a subclass of <a href="https://github.com/selenide/selenide/blob/master/src/main/java/com/codeborne/selenide/webdriver/ChromeDriverFactory.java">ChromeDriverFactory</a>, <a href="https://github.com/selenide/selenide/blob/master/src/main/java/com/codeborne/selenide/webdriver/FirefoxDriverFactory.java">FirefoxDriverFactory</a> or similar class (which exist in Selenide and implement interface <code class="language-plaintext highlighter-rouge">DriverFactory</code>) and override only needed methods. All methods in these classes are made small and declared protected.</li> </ol> <p>You can find examples in <a href="https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/ChromeProfileByFactoryTest.java">Selenide own tests</a>.</p> <p>See also <a href="https://mbbaig.blog/selenide-webdriverfactory/">blog post from Boris Bay</a>.</p> <p><br /> <a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2019/12/03/advent-calendar-set-webdriver-vs-webdriver-provider/ https://selenide.org/2019/12/03/advent-calendar-set-webdriver-vs-webdriver-provider 2019-12-03T00:00:00+00:00 How to abuse Selenide <p>Good year!</p> <p>It’s December, 02, and we continue with our Selenide Advent Calendar. This time will talk about invalid use of Selenide.</p> <h1 id="how-to-abuse-selenide">How to abuse Selenide</h1> <p>I often hear people complaining that the following code doesn’t catch the exception:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">try</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">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="s">".banner .close"</span><span class="o">).</span><span class="na">click</span><span class="o">();</span> <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span> <span class="c1">// System.out.println("The element is not found - a banner hasn't appeared this time.");</span> <span class="o">}</span> </code></pre></div></div> <p>The intention of this test is to check if a banner appeared. Not immediately, but wait for the banner a little bit: probably it will appear after some time. If the banner has appeared, the test needs to close it.</p> <p><br /></p> <h1 id="why-this-is-a-bad-test">Why this is a bad test?</h1> <p>Because <strong>it’s slow</strong>.</p> <p>In most cases, banner will not appear, and the test will waste 4 seconds (or what is your timeout).</p> <p>It’s awful. Are you a professional engineer? Your goal is to make your tests fast and stable.</p> <p><br /></p> <h1 id="why-this-test-is-very-bad">Why this test is very bad?</h1> <p>Because <strong>it’s unstable</strong>.</p> <p>Sometimes banner will appear in the end of 4th second. Test decides that banner hasn’t appeared and goes on. At this moment the banner appears. Ups, you get a flaky test.</p> <p><br /></p> <h1 id="why-this-test-is-very-very-bad">Why this test is very-very bad?</h1> <p>Because <strong>it doesn’t test the banner</strong>.</p> <ol> <li> <p>Imagine that banner hasn’t appeared during tests run. All tests are green. But in production, the banner appears for end-users. And when the banner appears, an error happens. The application crashes. Users complain. <br /> <br /> <em>But your tests are green.</em></p> </li> <li> <p>Imagine the opposite. During your tests run, banner appears all the time. Well, that’s what happened in the test environment. But real users see the banner very rarely, and the error happens when they don’t see the banner. The application crashes. Users complain. <br /> <br /> <em>But your tests are green.</em></p> </li> </ol> <p><br /></p> <h1 id="what-can-you-do">What can you do?</h1> <p>Obviously, you should have at least 2 tests:</p> <ol> <li>Case when the banner appears, and</li> <li>Case when the banner doesn’t appear.</li> </ol> <p>To achieve that, you need a possibility to rule the banner. You should be able to show or hide the banner either using some API or admin console or by running SQL in database. Whatever. Every mean is good. If you don’t have such API, you should make a deal with developers and create it.</p> <p>Don’t tell me that you can’t. Are you a professional engineer or what?</p> <p>If you cannot, just delete this test. Cannot means CAN NOT.</p> <p><br /></p> <p>And finally, the initial question:</p> <h1 id="why-that-code-doesnt-catch-the-exception">Why that code doesn’t catch the Exception?</h1> <p>You probably guessed it, right?</p> <p>The trick is with hierarchy of Java exceptions. The parent class of all java exceptions is <code class="language-plaintext highlighter-rouge">Throwable</code>, not <code class="language-plaintext highlighter-rouge">Exception</code>. Here is the hierarchy:</p> <ul> <li><code class="language-plaintext highlighter-rouge">Throwable</code> <ul> <li><code class="language-plaintext highlighter-rouge">Exception</code> <ul> <li><code class="language-plaintext highlighter-rouge">RuntimeException</code> <ul> <li><code class="language-plaintext highlighter-rouge">WebDriverException</code></li> </ul> </li> </ul> </li> <li><code class="language-plaintext highlighter-rouge">Error</code> <ul> <li><code class="language-plaintext highlighter-rouge">AssertionError</code> <ul> <li><code class="language-plaintext highlighter-rouge">UIAssertionError</code> <ul> <li><code class="language-plaintext highlighter-rouge">ElementShould</code></li> </ul> </li> </ul> </li> </ul> </li> </ul> </li> </ul> <p>This is the reason why you miss all <code class="language-plaintext highlighter-rouge">Error</code> subclasses (including Selenide errors) when you <code class="language-plaintext highlighter-rouge">catch (Exception e)</code>.</p> <p>You might think: “Great, I will <code class="language-plaintext highlighter-rouge">catch (Error e)</code>”. No. NO! Please, NO!</p> <p>Read the <code class="language-plaintext highlighter-rouge">java.lang.Error</code> javadoc:</p> <blockquote> <p>An Error is a subclass of Throwable that indicates serious problems that a reasonable application <strong>should not try to catch</strong>. Most such errors are abnormal conditions.</p> </blockquote> <h2 id="whats-now">What’s now?</h2> <p>I hope you will stop catching exceptions in tests. The goal of tests is to report errors, not catch them.</p> <p>I hope you will take the test environment under your control.</p> <p>You need to decide, either you rule the banner, or the banner rules you.</p> <p>Either you automate tests, or tests automate you.</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2019/12/02/advent-calendar-how-to-abuse-selenide/ https://selenide.org/2019/12/02/advent-calendar-how-to-abuse-selenide 2019-12-02T00:00:00+00:00 The Main Algorithm <p>Good December!</p> <p>The Advent has begun.</p> <p>Children are unpacking their advent calendars, opening one small window with a chocolate every day. In Java world, we have a <a href="https://www.javaadvent.com/">Java Advent Calendar</a>, in which many authors write a new article every day. I also participated in it could of times (<a href="https://www.javaadvent.com/2017/12/flaky-tests.html">2017</a> and <a href="https://www.javaadvent.com/2018/12/wtf-connection-pools.html">2018</a>).</p> <p>I also decided to start Selenide Advent Calendar. Every new day a new post. From 1st to 25th December. I am starting, and you can continue - just give me a notice by any possible way.</p> <p>Today topic is:</p> <h1 id="the-main-algorithm">The Main Algorithm</h1> <p>The main feature of Selenide, as many of you say, is <em>automated waiting</em>.<br /> You don’t need to copy-paste boilerplate code like <code class="language-plaintext highlighter-rouge">new WebDriverWait(driver, 30).until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[contains(text(),'COMPOSE')]")))</code> to wait for some event. You don’t need to waste your time and effort to decide where a waiting is needed. You don’t need to see a flaky tests and investigate where you should add one more <code class="language-plaintext highlighter-rouge">new WebDriverWait</code>.</p> <p>With Selenide, everything is much more simple. Any line like <code class="language-plaintext highlighter-rouge">$(byText("COMPOSE")).shouldBe(visible)</code> <strong>waits automatically</strong> if needed.</p> <h3 id="doesnt-it-slower-my-tests">Doesn’t it slower my tests?</h3> <p>No.</p> <p>If the element is already visible, Selenide will just go on. If not - Selenide will wait for 100 ms and check again. If still not, wait for another 100 ms and check again. So it will continue up to 4 seconds. And only if the element will not appear after 4 seconds, then Selenide will fail the test.</p> <p>Of course, those numbers 4s and 100ms are configurable.</p> <h3 id="how-it-works">How it works?</h3> <p>We are getting to the Main Algorithm. Actually, it’s very simple.</p> <p>For example, this is how <code class="language-plaintext highlighter-rouge">$(".btn").shouldBe(visible)</code> works:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">shouldBeVisible</span><span class="o">()</span> <span class="o">{</span> <span class="k">do</span> <span class="o">{</span> <span class="k">try</span> <span class="o">{</span> <span class="k">assert</span> <span class="n">webdriver</span><span class="o">.</span><span class="na">findElement</span><span class="o">().</span><span class="na">isDisplayed</span><span class="o">()</span> <span class="o">==</span> <span class="kc">true</span><span class="o">;</span> <span class="k">return</span> <span class="n">ok</span><span class="o">;</span> <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span> <span class="n">sleep</span><span class="o">(</span><span class="mi">100</span> <span class="n">ms</span><span class="o">)</span> <span class="o">}</span> <span class="o">}</span> <span class="k">while</span> <span class="o">(</span><span class="n">less</span> <span class="n">than</span> <span class="no">N</span> <span class="n">seconds</span><span class="o">);</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">ElementShouldBeVisible</span><span class="o">(</span><span class="s">"Expected: foo, actually: bar"</span><span class="o">);</span> <span class="c1">// and take a screenshot</span> <span class="o">}</span> </code></pre></div></div> <p>You see: the idea is really simple.</p> <p>In reality, this code <a href="https://github.com/selenide/selenide/blob/master/src/main/java/com/codeborne/selenide/impl/WebElementSource.java#L44">is a bit more complex</a>. It’s because it’s “generic” - not only for <code class="language-plaintext highlighter-rouge">shouldBe(visible)</code>, but for all other methods and conditions.</p> <p>As you know,</p> <h3 id="the-devil-is-in-the-details">the devil is in the details</h3> <p>In the code shown above, there is plenty of questions:</p> <ol> <li>Which exceptions to catch? <ul> <li><code class="language-plaintext highlighter-rouge">Exception</code>, <code class="language-plaintext highlighter-rouge">Error</code>, <code class="language-plaintext highlighter-rouge">Throwable</code>, <code class="language-plaintext highlighter-rouge">AssertionError</code>, <code class="language-plaintext highlighter-rouge">WebDriverException</code>?</li> </ul> </li> <li>In case of which exceptions should we stop the waiting and fail the test immediately? <ul> <li>for example, if XPath is invalid, it will remain invalid after 4 seconds too.</li> </ul> </li> <li>The result is ok or nok? <ul> <li>for example, if element is not found - it could be ok for condition <code class="language-plaintext highlighter-rouge">$.shouldNot(exist)</code>.</li> </ul> </li> <li>At what moment would we take screenshot?</li> <li>Can user customize any of these lines? <ul> <li>For example, it’s probably not needed to take a screenshot because Allure will take its own screenshot anyway.</li> <li>Or the opposite, we probably should take screenshot and pass it to Allure somehow?</li> <li>(currently both Selenide and Allure take a screenshot, so they are duplicated)</li> </ul> </li> <li>What if we run until the last line, and during execution of the last line we got a fu#ng <code class="language-plaintext highlighter-rouge">StaleElementException</code>?</li> </ol> <p>Our answers to these questions have been changing in time. And will probably change. But the essence remains.</p> <h2 id="whats-now">What’s now?</h2> <p>I hope you will now understand Selenide waiting instead of perceiving it as a “black magic”. It will probably help you during debugging of some corner cases and mystical test failures.</p> <p>And you can even suggest an idea how to improve or simplify the <s>Skynet core</s> Main Algorithm.</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2019/12/01/advent-calendar-main-algorithm/ https://selenide.org/2019/12/01/advent-calendar-main-algorithm 2019-12-01T00:00:00+00:00 Released Selenide 5.5.1 <p>Hi all!</p> <p>At Black Friday, we released <a href="https://github.com/selenide/selenide/milestone/86?closed=1">Selenide 5.5.1</a> with a couple of new features.</p> <ul> <li><a href="#mobile-browser-emulation">Mobile browser emulation</a></li> <li><a href="#deprecated-selenide-close">Deprecated method <code class="language-plaintext highlighter-rouge">Selenide.close()</code></a></li> <li><a href="#news">News</a></li> </ul> <p><br /></p> <h1 id="mobile-browser-emulation">We added mobile browser emulation</h1> <p>Sometimes you want to run browser not on a usual Chrome, but on Chrome “like in mobile”.</p> <p>Like you would open a browser in mobile phone or tablet.</p> <p>(For example, site selenide.org looks ugly on mobile. :( We are working on it.)</p> <p>Now it’s easy to do it by adding a System property before running tests:</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>or right in your 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.mobileEmulation"</span><span class="o">,</span> <span class="s">"deviceName=Nexus 5"</span><span class="o">);</span> </code></pre></div></div> <p>NB! We are talking only about one setting - a device name. It should be enough in most cases. If you need to tune other mobile browser settings, please implement <code class="language-plaintext highlighter-rouge">WebDriverProvider</code> interface.</p> <p>See <a href="https://github.com/selenide/selenide/issues/1008">issue 1008</a> and <a href="https://github.com/selenide/selenide/pull/1011">PR 1011</a>.</p> <p><br /></p> <h1 id="deprecated-selenide-close">We deprecated method <code class="language-plaintext highlighter-rouge">Selenide.close()</code></h1> <p>Selenide always had method <code class="language-plaintext highlighter-rouge">Selenide.close()</code>. But its name is misleading: it closes the whole browser, not only a current window. The problem is that Selenium Webdriver also has method <code class="language-plaintext highlighter-rouge">close()</code> which only closes a current window/tab (and the whole browser only if it was the only window/tab). And for closing the whole browser Selenium has method <code class="language-plaintext highlighter-rouge">quit()</code>.</p> <p>It was my fault that I created method <code class="language-plaintext highlighter-rouge">close()</code> without reading Selenium documentation. I was young and didn’t believe in Javadoc. :) But part of the problem is that Selenium names <code class="language-plaintext highlighter-rouge">close</code> vs <code class="language-plaintext highlighter-rouge">quit</code> are not intuitive. Go figure which of them closes what.</p> <p>To make your life easier, we now suggest two method with explicit names:</p> <ul> <li><code class="language-plaintext highlighter-rouge">Selenide.closeWindow()</code> - closes a current window (or tab, which is the same)</li> <li><code class="language-plaintext highlighter-rouge">Selenide.closeWebDriver()</code> - closes the whole browser</li> </ul> <p>Now you don’t need to remember anything.</p> <p>The old method <code class="language-plaintext highlighter-rouge">Selenide.close()</code> is now deprecated. Going to delete it in Selenide 6.0.0</p> <p>See <a href="https://github.com/selenide/selenide/issues/1016">issue 1016</a> and <a href="https://github.com/selenide/selenide/pull/1017">PR 1017</a>.</p> <p><br /></p> <h2 id="news">News</h2> <ul> <li>Wow! A new IDEA plugin for Selenide/Selenium: <a href="https://plugins.jetbrains.com/plugin/13267-qa-lithium">QA Lithium</a>. Thanks to <a href="https://strangeway.org/">Yuriy Artamonov</a>!</li> <li>Another framework on top of Selenide: <a href="https://github.com/cuba-platform/masquerade">Masquerade</a> - <em>CUBA Platform UI Testing Library</em></li> <li>Article <a href="https://medium.com/swlh/selenide-in-testing-process-automatisation-through-selenoid-in-the-docker-container-48e659d2ee72">about Selenide and Selenoid</a></li> <li>Another article <a href="https://www.intexsoft.com/blog/post/selenide-docker.html">about Selenide and Selenoid</a></li> </ul> <p><br /></p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2019/11/29/selenide-5.5.1/ https://selenide.org/2019/11/29/selenide-5.5.1 2019-11-29T00:00:00+00:00 Released Selenide 5.5.0 <p>Good evening!</p> <p>How do you celebrate Halloween?</p> <p>We released <a href="https://github.com/selenide/selenide/milestone/85?closed=1">Selenide 5.5.0</a> with some <em>backward incompatible changes</em>.</p> <p>ARE YOU SCARED?</p> <p><br /></p> <h1 id="migrated-from-jul-to-slf4j">Migrated from JUL to SLF4J</h1> <p>Sometimes Selenide needs to write down some diagnostic logs, like “I found browser binary in foo”, “I failed to save screenshot to bar” etc.</p> <p>Until now, Selenide did write its logs using Java built-in mechanism <code class="language-plaintext highlighter-rouge">java.util.logging</code> (aka JUL). It has some known disadvantages, that’s why there is plenty of alternatives in the Java world: Log4J, Slf4j, Logback, JCL.</p> <p>How it works:</p> <ul> <li>Slf4J is a “facade”, something like “interface”. Selenide will write logs using it.</li> <li>And Log4j, Logback, JCL are implementations of this “interface” (probably there are more of them).</li> </ul> <p>You decide which implementation of Slf4J you want to use. Most probably this decision is already done in your project, because at least WebDriverManager always wrote logs using Slf4J.</p> <p>To use one of Slf4J implementations, you need to add corresponding dependency to your project:</p> <ul> <li>slf4j-log4j12-*.jar</li> <li>logback-classic-*.jar</li> <li>slf4j-simple-*.jar</li> <li>slf4j-jdk14-*.jar</li> <li>slf4j-jcl-*.jar</li> <li>slf4j-nop-*.jar (NO! Please DON’T! It just ignores all logs.)</li> </ul> <p>NB! Let me remind: most probably you already have one of these dependencies. So you don’t need to do anything.</p> <p>If you still don’t have any of these dependencies, you will see such message when running tests (I will not see Selenide logs):</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. </code></pre></div></div> <p>If you see it, probably the easiest solution would be to add one line to your build.gradle:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>testRuntimeOnly 'org.slf4j:slf4j-simple:1.7.28' </code></pre></div></div> <p>or in pom.xml:</p> <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;dependency&gt;</span> <span class="nt">&lt;groupId&gt;</span>org.slf4j<span class="nt">&lt;/groupId&gt;</span> <span class="nt">&lt;artifactId&gt;</span>slf4j-simple<span class="nt">&lt;/artifactId&gt;</span> <span class="nt">&lt;version&gt;</span>1.7.28<span class="nt">&lt;/version&gt;</span> <span class="nt">&lt;scope&gt;</span>test<span class="nt">&lt;/scope&gt;</span> <span class="nt">&lt;/dependency&gt;</span> </code></pre></div></div> <p>NB! If you failed to setup Slf4j - don’t panic. Selenide logs are not so much important. Test failures will not disappear. We are only talking about diagnostic INFO and WARNING logs like <code class="language-plaintext highlighter-rouge">INFO Using browser binary: /var/lib/opera.exe</code>.</p> <p>See <a href="https://github.com/selenide/selenide/issues/923">923</a>.</p> <p>Thanks to <a href="https://github.com/gschukin">Gleb Schukin</a> for <a href="https://github.com/selenide/selenide/pull/926">PR 926</a>.</p> <p><br /></p> <h1 id="removed-htmlunit-and-phantomjs-dependencies">Removed HtmlUnit and PhantomJS dependencies</h1> <p>Don’t be afraid, your tests should still work with HtmlUnit and PhantomJS. Just Selenide will not bring these dependencies transitively (because most of people already migrated to <em>headless chrome</em> and <em>headless firefox</em>).</p> <p>If you still want to use HtmlUnit or PhantomJS, you just need to add corresponding dependencies to your project.</p> <p>Thanks to <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/1003">PR 1003</a> and <a href="https://github.com/selenide/selenide/pull/998">PR 998</a>.</p> <p><br /></p> <h1 id="removed-built-in-support-for-safari-browser">Removed built-in support for Safari browser</h1> <p>But don’t worry, you can still use Safari! See the <a href="https://github.com/selenide/selenide/wiki/Safari">instruction</a></p> <p><br /></p> <h1 id="made-method-executecommand-generic">Made method <code class="language-plaintext highlighter-rouge">$.execute(command)</code> generic</h1> <p>Before now, method<code class="language-plaintext highlighter-rouge">$.execute</code> accepted only <code class="language-plaintext highlighter-rouge">Command&lt;SelenideElement&gt;</code>, but now it can accept any <code class="language-plaintext highlighter-rouge">Command</code>s.</p> <p>See <a href="https://github.com/selenide/selenide/issues/1000">issue 1000</a> and <a href="https://github.com/selenide/selenide/pull/1001">PR 1001</a>.</p> <p><br /></p> <h1 id="fixed-setting-holdbrowseropen">Fixed setting <code class="language-plaintext highlighter-rouge">holdBrowserOpen</code></h1> <p>.. which we broke in Selenide 5.4.1. Now browser is left opened again, and you can investigate your failed tests.</p> <p>See <a href="https://github.com/selenide/selenide/issues/999">issue 999</a> and <a href="https://github.com/selenide/selenide/pull/1005">PR 1005</a>.</p> <p><br /></p> <h1 id="take-a-screenshot-in-case-of-dialogtextmismatch-error">Take a screenshot in case of <code class="language-plaintext highlighter-rouge">DialogTextMismatch</code> error</h1> <p>As you know, Selenide has a method for verifying text of modal dialog (<code class="language-plaintext highlighter-rouge">alert</code> or <code class="language-plaintext highlighter-rouge">confirm</code>):</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">confirm</span><span class="o">(</span><span class="s">"Are you sure?"</span><span class="o">);</span> </code></pre></div></div> <p>But when this check failed, Selenide forgot to take a screenshot. Now it’s fixed.</p> <p>See <a href="https://github.com/selenide/selenide/issues/907">issue 907</a>. Thanks to <a href="https://github.com/nwholloway">Nick Holloway</a> for <a href="https://github.com/selenide/selenide/pull/986">PR 986</a>.</p> <p><br /></p> <h1 id="refactoring-of-screenshotlaboratory">Refactoring of <code class="language-plaintext highlighter-rouge">ScreenShotLaboratory</code></h1> <p>Though it’s just a refactoring, and it will not affect you, I must mention the initiative of <a href="https://github.com/SeleniumTestAB">SeleniumTestAB</a> who decided to improve Selenide code and sent <a href="https://github.com/selenide/selenide/pull/1004">PR 1004</a> and <a href="https://github.com/selenide/selenide/pull/1006">PR 1006</a>.</p> <p>Good job!</p> <p><br /></p> <h2 id="news">News</h2> <ul> <li>Presentation about Selenide on EclipseCon 2019: <a href="https://www.eclipsecon.org/europe2019/sessions/complete-selenium-techstack-conception-evaluation-open-source-software">A complete Selenium Techstack</a></li> <li>My presentation for Cyprus Quality Conference <a href="https://docs.google.com/presentation/d/1hSCmjwvLCY4bKqSncffZfMOi1NmXIooJu5LIjxYN6hg/edit">Threesome: Selenide for Web, Android and iOS”</a>. So far, only slides.</li> </ul> <h2 id="and-the-most-important">And the most important!</h2> <p><strong>Selenide got 8 years old</strong>!</p> <p>25.10.2011 a first commit to Selenide was done.</p> <p>After 8 years, we have:</p> <ul> <li>89K downloads from 14K unique IPs (per month)</li> <li>1K stars on github</li> <li>55 contributors</li> </ul> <p>Many thanks to all contributors, users, critics, ideologists and just sympathizers.</p> <p>This is just the beginning :)</p> <p><br /></p> <p>Selenide download statistics for October, 2019:</p> <center> <img src="/images/2019/10/selenide.downloads.png" width="800" /> </center> <p><br /></p> <center> <img src="/images/2019/10/selenide.unique-ips.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> https://selenide.org/2019/10/31/selenide-5.5.0/ https://selenide.org/2019/10/31/selenide-5.5.0 2019-10-31T00:00:00+00:00 Released Selenide 5.4.1 <p>Good evening!</p> <p>There is nothing in the World more boring than October. Let’s brighten it up with bright news!</p> <p>Today we released Selenide 5.4.0 with a couple of noticeable changes <em>which many of you have been asking for a while</em>.</p> <p><strong>UPD</strong> There was a bug in 5.4.0, so please upgrade to <strong>5.4.1</strong></p> <p><strong>UPD 2</strong> There is also a minor bug in 5.4.1: <code class="language-plaintext highlighter-rouge">Configuration.holdBrowserOpen</code> doesn’t work. Will fix it in next version. I hope you don’t use it often.</p> <p><br /></p> <h1 id="fix-illegal-state-exception">1. Fixed “IllegalStateException WebDriver has been closed”</h1> <p>Starting from Selenide 5.0.0 (~1 year ago), many users started complaining about <br /> <code class="language-plaintext highlighter-rouge">IIlegalStateException WebDriver has been closed...</code>.</p> <p>Actually it’s not a bug, it was intended behaviour. I didn’t want to fix it for a while because I believe such an exception cannot happen in well-designed tests. Selenide threw in intentionally to stimulate people design their tests better.</p> <p>But we had too many complaints, so I decided to remove this exception - <em>with a heavy heart</em>!</p> <blockquote> <p>In the end, everyone has the right to fill their own bumps.</p> </blockquote> <h3 id="how-this-error-happened">How this error happened?</h3> <p>Shortly speaking, this exception happens when instance of <code class="language-plaintext highlighter-rouge">SelenideElement</code> is reused with multiple instances of <code class="language-plaintext highlighter-rouge">SelenideDriver</code>. It can happen when <code class="language-plaintext highlighter-rouge">SelenideElement</code> is declared as a static field (either of a page object or a test). And is initialized before the browser is opened. Or browser is restarted between tests. It also may happen when people use Cucumber which tries to initialize step objects, page objects before opening a browser. Some folks also put Guice or Spring to their test.</p> <p>All of this is over-engineering. It’s just not needed.</p> <p>People, you don’t need all these things in tests. Tests must be simple. KISS, <em>amen</em>!</p> <p>Watch this presentation to know why <a href="https://www.youtube.com/watch?v=dFQSOlOOoXE&amp;t=1s">Static fields are evil</a>.</p> <h3 id="whats-changed">What’s changed?</h3> <p>But well, people can have different opinions. <em>As a sign of tolerance</em>, let’s meet Selenide 5.4.0</p> <p>Now this code will work without exceptions:</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">SomeClass</span> <span class="o">{</span> <span class="kd">private</span> <span class="kd">static</span> <span class="nc">SelenideElement</span> <span class="n">body</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"body"</span><span class="o">);</span> <span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span> <span class="n">open</span><span class="o">(</span><span class="s">"https://mail.ru"</span><span class="o">);</span> <span class="n">body</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="nc">Selenide</span><span class="o">.</span><span class="na">close</span><span class="o">();</span> <span class="n">open</span><span class="o">(</span><span class="s">"https://mail.ru"</span><span class="o">);</span> <span class="n">body</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="c1">// it threw "IllegalStateException WebDriver has been closed" before Selenide 5.4.0</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div></div> <p>You can find more examples and complaints in issues <a href="https://github.com/selenide/selenide/issues/862">862</a>, <a href="https://github.com/selenide/selenide/issues/902">902</a>, <a href="https://github.com/selenide/selenide/issues/954">954</a>, <a href="https://github.com/selenide/selenide/issues/922">922</a>, <a href="https://github.com/selenide/selenide/issues/873">873</a>.</p> <p>If you are interested in implementation details, welcome to <a href="https://github.com/selenide/selenide/pull/989">PR 989</a>.</p> <p><br /></p> <h1 id="close-always-closes-browser">2. Now method <code class="language-plaintext highlighter-rouge">SelenideDriver.close()</code> always closes the browser</h1> <p>Starting from Selenide 5.0.0, people started complaining that method <code class="language-plaintext highlighter-rouge">close()</code> doesn’t close the browser. It happened in (rare) cases when browser was opened by user code, not Selenide.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">SelenideDriver</span> <span class="n">browser</span><span class="o">=</span><span class="k">new</span> <span class="nc">SelenideDriver</span><span class="o">(</span><span class="k">new</span> <span class="nc">FirefoxDriver</span><span class="o">());</span> <span class="n">browser</span><span class="o">.</span><span class="na">close</span><span class="o">();</span> <span class="c1">// it didn't close the browser</span> <span class="n">browser</span><span class="o">.</span><span class="na">getWebDriver</span><span class="o">().</span><span class="na">close</span><span class="o">();</span> <span class="c1">// it did close the browser</span> </code></pre></div></div> <p>Actually it’s not a bug, it was intended behaviour. Selenide initially has this principle: it closed only the browser opened by Selenide itself. And never closed the browser opened by user: it might be used somewhere else.</p> <p>But again, we had a lot of complaints. It caused a hassle: you see method <code class="language-plaintext highlighter-rouge">close()</code>, you call it, it works without exceptions - but the browser is still open.</p> <p>Now we fixed it. Method <code class="language-plaintext highlighter-rouge">close()</code> always closes the browser.</p> <p>P.S. If your browser is now being unexpectedly closed - feel free to fire a github issue, we will investigate it.</p> <p>See <a href="https://github.com/selenide/selenide/issues/896">issue 896</a> and <a href="https://github.com/selenide/selenide/pull/989">PR 989</a></p> <p><br /></p> <h1 id="restore-short-error-messages">3. We restored short human-readable error messages</h1> <p>You might notice that Selenide 5.3.1 introduced one minor issue. Error messages became longer and hard to read:</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">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">ex</span><span class="o">.</span><span class="na">ElementNotFound</span><span class="o">:</span> <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">customerDashboardButton</span><span class="o">}</span> </code></pre></div></div> <p>Now we returned the old good human-readable messages:</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">customerDashboardButton</span><span class="o">}</span> </code></pre></div></div> <p>P.S. Poor users of <code class="language-plaintext highlighter-rouge">maven-surefire-plugin 2.22.2</code> will still have long messages, <a href="/2019/09/07/selenide-5.3.1/">see details here</a>.</p> <p>See <a href="https://github.com/selenide/selenide/pull/993">PR 993</a></p> <p><br /></p> <h1 id="add-method-using">4. Added method <code class="language-plaintext highlighter-rouge">using</code> for easier switching between multiple webdrivers</h1> <p>As I already <a href="/2018/10/10/selenide-5.0.0/">said before</a>, using of multiple webdrivers in one test is a bad practice in absolutely most cases.</p> <p>But again, everyone has the right to fill their own bumps. Now it’s a little more easier to fill that bumps with multiple webdrivers.</p> <p>Before Selenide 5.4.0, you had to call <code class="language-plaintext highlighter-rouge">setWebDriver()</code> all the time - and keep in mind which browser is active at the moment:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">browser1</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">FirefoxDriver</span><span class="o">();</span> <span class="kt">var</span> <span class="n">browser2</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">FirefoxDriver</span><span class="o">();</span> <span class="n">setWebDriver</span><span class="o">(</span><span class="n">browser1</span><span class="o">);</span> <span class="n">open</span><span class="o">(</span><span class="s">"http://google.com"</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">"Released Selenide 5.4.0"</span><span class="o">));</span> <span class="n">setWebDriver</span><span class="o">(</span><span class="n">browser2</span><span class="o">);</span> <span class="n">open</span><span class="o">(</span><span class="s">"http://yandex.ru"</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">"Released Selenide 5.4.0"</span><span class="o">));</span> </code></pre></div></div> <p>now you can wrap code blocks for different browsers in separate <code class="language-plaintext highlighter-rouge">using</code> calls:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">browser1</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">FirefoxDriver</span><span class="o">();</span> <span class="kt">var</span> <span class="n">browser2</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">FirefoxDriver</span><span class="o">();</span> <span class="n">using</span><span class="o">(</span><span class="n">browser1</span><span class="o">,</span> <span class="o">()</span> <span class="o">-&gt;</span> <span class="o">{</span> <span class="n">open</span><span class="o">(</span><span class="s">"http://google.com"</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">"Released Selenide 5.4.0"</span><span class="o">));</span> <span class="o">});</span> <span class="n">using</span><span class="o">(</span><span class="n">browser2</span><span class="o">,</span> <span class="o">()</span> <span class="o">-&gt;</span> <span class="o">{</span> <span class="n">open</span><span class="o">(</span><span class="s">"http://yandex.ru"</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">"Released Selenide 5.4.0"</span><span class="o">));</span> <span class="o">});</span> </code></pre></div></div> <p>See <a href="https://github.com/selenide/selenide/pull/976">PR 976</a> and code samples in <a href="https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/CustomWebdriverTest.java">CustomWebdriverTest.java</a>.</p> <p><br /></p> <h1 id="add-xpath-sanity-check">5. Added protection against one typical error with xpath</h1> <p>Here is the typical error:</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">".parent"</span><span class="o">).</span><span class="na">find</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">"/child"</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>The problem is that XPath starting with a slash (“/”) looks for element <strong>from the root of the document</strong> (not from <code class="language-plaintext highlighter-rouge">.parent</code> element).</p> <p>We added a protection. Now this code will throw an exception which clearly states the problem and saves your time:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">IllegalArgumentException:</span> <span class="nc">XPath</span> <span class="n">starting</span> <span class="n">from</span> <span class="o">/</span> <span class="n">searches</span> <span class="n">from</span> <span class="n">root</span> </code></pre></div></div> <p>The code above can be fixed in different ways (depending on what you actually need):</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">".parent"</span><span class="o">).</span><span class="na">find</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">"./child"</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="s">".parent"</span><span class="o">).</span><span class="na">find</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">".//child"</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="s">".parent"</span><span class="o">).</span><span class="na">find</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">"child"</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>See <a href="https://github.com/selenide/selenide/pull/963">PR 963</a> and <a href="https://github.com/selenide/selenide/pull/975">PR 975</a>.</p> <p><br /></p> <h1 id="update-dependencies">6. Upgraded dependencies</h1> <ul> <li>upgrade to webdrivermanager:3.7.1</li> <li>exclude old Guava dependency coming from net.lightbody.bmp:browsermob-core:2.1.5</li> </ul> <p>Just in case, we discovered a bug in WDM: when you want to download chromedriver 77, it may download “75.0.3770.90” instead. It’s because this version contains substring “77”. <a href="https://github.com/bonigarcia/webdrivermanager/issues/391">Isn’t it funny?</a> :)</p> <p><br /></p> <h2 id="news">News</h2> <ul> <li>A new utility <a href="https://github.com/bsideup/jabel">Jabel</a> from Sergei Egorov: <br />now you can write code in Java13 but compile to Java8. <em>Unbelievable, but it’s possible!</em></li> <li>Video <a href="https://www.youtube.com/watch?v=WNzTuYFd8oI">about Selenide in German</a></li> <li>English-speaking world <a href="https://testguild.com/selenide/">discovers Selenide</a>. The post also contains a link to a podcast about Selenide.</li> <li>Martin Škarbala from Slovakia added english subtitles to his great video about Selenide: <br /> <a href="https://www.youtube.com/watch?v=y9WTRTOTOsc">Selenide - stručné UI testy</a>.</li> <li><a href="https://vimeo.com/363993082">The World Needs Full-Stack Craftsmen</a> - Anton Keks, GeekOut, Tallinn, 26.09.2019</li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2019/10/16/selenide-5.4.0/ https://selenide.org/2019/10/16/selenide-5.4.0 2019-10-16T00:00:00+00:00 Released Selenide 5.3.1 <p>Hi all!</p> <p>There was a sensation:</p> <p><strong>The presentation of the new iPhone went unnoticed!</strong></p> <p>Because we released Selenide 5.3.1. With improved shots as well. :)</p> <p>We fixed only one problem in this version, but what problem is it!</p> <p><br /></p> <h1 id="maven-where-are-my-screenshots">Maven, where are my screenshots?</h1> <p>Recently we discovered that users of Maven and latest <code class="language-plaintext highlighter-rouge">maven-surefire-plugin:2.22.2</code> were deprived of one of the most important selenide features: screenshot was not added to the error report.</p> <p>That was unexpected!</p> <p><strong>How did you even live without it, poor fellows?</strong></p> <p><em>Probably that’s why you think you need BDD, Serenity and Allure?</em> Probably you don’t need. :)</p> <p>Read on.</p> <p><br /></p> <h1 id="see-the-difference">See the difference</h1> <p>That’s how error report looks in Maven and latest <code class="language-plaintext highlighter-rouge">maven-surefire-plugin:2.22.2</code>:</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">codeborne</span><span class="o">.</span><span class="na">selenide</span><span class="o">.</span><span class="na">ex</span><span class="o">.</span><span class="na">ListSizeMismatch</span><span class="o">:</span> <span class="o">:</span> <span class="nl">expected:</span> <span class="o">=</span> <span class="mi">11</span><span class="o">,</span> <span class="nl">actual:</span> <span class="mi">0</span><span class="o">,</span> <span class="nl">collection:</span> <span class="o">.</span><span class="na">results</span> <span class="nl">Elements:</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">GoogleTest</span><span class="o">.</span><span class="na">openGoogle</span><span class="o">(</span><span class="nc">GoogleTest</span><span class="o">.</span><span class="na">java</span><span class="o">:</span><span class="mi">42</span><span class="o">)</span> </code></pre></div></div> <p>You don’t see a screenshot. Bad luck.</p> <p>And this is how error report looks in Gradle, Ant, any IDE and default <code class="language-plaintext highlighter-rouge">maven-surefire-plugin:2.12.4</code>:</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="n">mismatch</span><span class="o">.</span> <span class="nl">Expected:</span> <span class="o">=</span> <span class="mi">11</span><span class="o">,</span> <span class="nl">actual:</span> <span class="mi">0</span><span class="o">,</span> <span class="nl">collection:</span> <span class="o">.</span><span class="na">results</span> <span class="nl">Elements:</span> <span class="o">[]</span> <span class="nl">Screenshot:</span> <span class="nl">file:</span><span class="o">/</span><span class="nc">Users</span><span class="o">/</span><span class="n">andrei</span><span class="o">/</span><span class="n">projects</span><span class="o">/</span><span class="n">selenide</span><span class="o">-</span><span class="n">examples</span><span class="o">/</span><span class="n">sandbox</span><span class="o">-</span><span class="n">selenide</span><span class="o">-</span><span class="n">junit5</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="mf">1567803355181.0</span><span class="o">.</span><span class="na">png</span> <span class="nc">Page</span> <span class="nl">source:</span> <span class="nl">file:</span><span class="o">/</span><span class="nc">Users</span><span class="o">/</span><span class="n">andrei</span><span class="o">/</span><span class="n">projects</span><span class="o">/</span><span class="n">selenide</span><span class="o">-</span><span class="n">examples</span><span class="o">/</span><span class="n">sandbox</span><span class="o">-</span><span class="n">selenide</span><span class="o">-</span><span class="n">junit5</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="mf">1567803355181.0</span><span class="o">.</span><span class="na">html</span> <span class="nl">Timeout:</span> <span class="mi">4</span> <span class="n">s</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">GoogleTest</span><span class="o">.</span><span class="na">openGoogle</span><span class="o">(</span><span class="nc">GoogleTest</span><span class="o">.</span><span class="na">java</span><span class="o">:</span><span class="mi">42</span><span class="o">)</span> </code></pre></div></div> <p>Now you see a screenshot in case of test failure. It’s enough to investigate the reason of test failure. You just don’t need any “nice” reports, BDD, report portals etc.</p> <p><em>Now we are talking!</em></p> <p><br /></p> <h1 id="investigation">Investigation</h1> <p>But why it happened?</p> <ol> <li>In Java, there is a class <code class="language-plaintext highlighter-rouge">Throwable</code> which is a parent of all errors and exceptions.</li> <li>It has 2 important methods: <code class="language-plaintext highlighter-rouge">getMessage()</code> and <code class="language-plaintext highlighter-rouge">toString()</code>.</li> <li>by default <code class="language-plaintext highlighter-rouge">toString()</code> = <code class="language-plaintext highlighter-rouge">class name</code> + <code class="language-plaintext highlighter-rouge">getMessage()</code></li> </ol> <p>For example, the following code</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">Throwable</span> <span class="n">e</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">IllegalArgumentException</span><span class="o">(</span><span class="s">"nope"</span><span class="o">);</span> <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">e</span><span class="o">.</span><span class="na">getMessage</span><span class="o">());</span> <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">e</span><span class="o">.</span><span class="na">toString</span><span class="o">());</span> </code></pre></div></div> <p>prints out:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">nope</span> <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="n">nope</span> </code></pre></div></div> <p>Initially, Selenide added screenshot name in method <code class="language-plaintext highlighter-rouge">UIAssertionError.toString()</code>. And it worked fine in Gradle, Ant, all IDEs. And in Maven too - in case of default <code class="language-plaintext highlighter-rouge">maven-surefire-plugin</code> version.</p> <p><br /></p> <h3 id="so-what-was-updated-in-maven">So what was updated in Maven?</h3> <p>There are funny guys working on Maven.</p> <ol> <li>Maven has 2 plugins for tests, not one.</li> <li>These plugins are named “surefire”, not “test” (which would be intuitive and clear for everyone)</li> <li>The latest Maven 3.6.2 by default uses <em>different versions</em> of those plugins: <ul> <li><code class="language-plaintext highlighter-rouge">maven-surefire-plugin:2.12.4</code> - <strong>7 years old</strong> (e.g. doesn’t support Java 11)</li> <li>and <em>unexpectedly</em> <br /><code class="language-plaintext highlighter-rouge">maven-surefire-report-plugin:3.0.0-M3</code> - <strong>beta version</strong>, not ready for production</li> </ul> </li> </ol> <p><br /></p> <p>Now, if you upgrade to latest <code class="language-plaintext highlighter-rouge">maven-surefire-plugin</code> in your pom.xml:</p> <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt">&lt;plugin&gt;</span> <span class="nt">&lt;groupId&gt;</span>org.apache.maven.plugins<span class="nt">&lt;/groupId&gt;</span> <span class="nt">&lt;artifactId&gt;</span>maven-surefire-plugin<span class="nt">&lt;/artifactId&gt;</span> <span class="nt">&lt;version&gt;</span>2.22.2<span class="nt">&lt;/version&gt;</span> <span class="nt">&lt;/plugin&gt;</span> </code></pre></div></div> <p>test reports start changing. Instead of <code class="language-plaintext highlighter-rouge">e.toString()</code> it now uses <code class="language-plaintext highlighter-rouge">class name + getMessage()</code>. That’s why screenshots are not appended to error report anymore.</p> <p><br /></p> <h1 id="how-we-fixed-it">How we fixed it?</h1> <p>Simple. We now add screenshot in method <code class="language-plaintext highlighter-rouge">e.getMessage()</code> instead of <code class="language-plaintext highlighter-rouge">e.toString()</code>. Sound simple, but we had to refactor all Selenide exceptions and fix many tests.</p> <p>Probably something went wrong, so feel free to <strong>file issues</strong>, if you wish some error messages to be improved!</p> <p>All the background and code modifications can be found here:</p> <ul> <li><a href="https://github.com/selenide/selenide/issues/234">issue 234</a></li> <li><a href="https://github.com/selenide/selenide/pull/972">PR 972</a></li> </ul> <p><br /></p> <h2 id="news">News</h2> <p>Selenide goes over the world!</p> <ul> <li>Look, what a <a href="https://www.youtube.com/watch?v=y9WTRTOTOsc">great video</a> created Martin Škarbala from Slovakia. In just a 1.5 minutes he demonstrates benefits of Selenide, and how much of boilerplate code you can delete after migration to Selenide.</li> </ul> <p><br /></p> <h2 id="conferences">Conferences</h2> <ul> <li>September, 20-21 - I will give two talks at <a href="http://qafest.com/en/">QA Fest</a> conference - Kyiv, Ukraine</li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2019/09/07/selenide-5.3.1/ https://selenide.org/2019/09/07/selenide-5.3.1 2019-09-07T00:00:00+00:00 Released Selenide 5.3.0 <p>We released Selenide 5.3.0. What’s new?</p> <p><br /></p> <h1 id="968-execute-custom-commands">#968 Execute custom commands</h1> <p>You will like this feature!</p> <p>I believe your code is fill of custom methods for operating web elements. You use some tricky double click, select some non-standard radio button on ReactJS, pick a date from hipster datepicker and upload a file from hidden input.</p> <p>Now we added a convenient way to execute such commands in one line. You just need to call method <code class="language-plaintext highlighter-rouge">$.execute</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kt">var</span> <span class="n">turnCalendar</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Command</span><span class="o">&lt;</span><span class="nc">SelenideElement</span><span class="o">&gt;()</span> <span class="o">{...};</span> <span class="kt">var</span> <span class="n">pickDate</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Command</span><span class="o">&lt;</span><span class="nc">SelenideElement</span><span class="o">&gt;()</span> <span class="o">{...};</span> <span class="err">$</span><span class="o">(</span><span class="s">"hiddenFileInput"</span><span class="o">).</span><span class="na">execute</span><span class="o">(</span><span class="n">turnCalendar</span><span class="o">).</span><span class="na">execute</span><span class="o">(</span><span class="n">pickDate</span><span class="o">(</span><span class="s">"03.09"</span><span class="o">);</span> </code></pre></div></div> <p>Thanks to <a href="https://github.com/rosolko">Aleksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/968">pull request 968</a>.</p> <p><br /></p> <h1 id="970-improved-error-message-for-shouldhaveattributehref-">#970 Improved error message for <code class="language-plaintext highlighter-rouge">shouldHave(attribute("href", ..."))</code></h1> <p>Folks reported a strange problem: <code class="language-plaintext highlighter-rouge">href</code> is the same, but test fails:</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">attribute</span> <span class="n">href</span><span class="o">=</span><span class="s">"/files/hello_world.txt"</span> <span class="o">{</span><span class="n">by</span> <span class="nl">text:</span> <span class="nc">Download</span> <span class="n">me</span><span class="o">}</span> <span class="nl">Element:</span> <span class="err">'</span><span class="o">&lt;</span><span class="n">a</span> <span class="n">href</span><span class="o">=</span><span class="s">"/files/hello_world.txt"</span><span class="o">&gt;</span><span class="nc">Download</span> <span class="n">me</span><span class="o">&lt;/</span><span class="n">a</span><span class="o">&gt;</span><span class="err">'</span> </code></pre></div></div> <p>The problem is with one nuance in Selenium: method <code class="language-plaintext highlighter-rouge">WebElement.getAttribute("href")</code> returns absolute URL, even if <code class="language-plaintext highlighter-rouge">href</code> contains a relative URL.<br /></p> <p>Actually we haven’t fixed this nuance, but improved the error message. Now it shows the actual value of the attribute:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Actual</span> <span class="nl">value:</span> <span class="n">href</span><span class="o">=</span><span class="s">"http://my-test-env.com:9999/files/hello_world.txt"</span> </code></pre></div></div> <p><br /></p> <h1 id="469-improved-error-messages-for-or-checks">#469 Improved error messages for OR checks</h1> <p>Probably you know that Selenide allows you to check one of multiple conditions (OR operand). It’s useful when you need to check if first OR second condition is matched (or both).</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#agree"</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">or</span><span class="o">(</span><span class="s">"checked"</span><span class="o">,</span> <span class="n">attribute</span><span class="o">(</span><span class="s">"checked"</span><span class="o">,</span> <span class="s">"true"</span><span class="o">),</span> <span class="n">attribute</span><span class="o">(</span><span class="s">"checked"</span><span class="o">,</span> <span class="s">"on"</span><span class="o">)</span> <span class="o">));</span> </code></pre></div></div> <p><br /></p> <p>The problem was: when such a test failed, it reported an invalid error message. It included only the first condition:</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">attribute</span> <span class="err">'</span><span class="n">attribute</span> <span class="n">checked</span><span class="err">'</span> <span class="o">{</span><span class="n">input</span><span class="err">#</span><span class="n">agree</span><span class="o">}</span><span class="err">"</span> </code></pre></div></div> <p><br /></p> <p>We have fixed it. Now it reports all conditions from OR block:</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="nl">checked:</span> <span class="n">attribute</span> <span class="err">'</span><span class="kc">true</span><span class="err">'</span> <span class="n">or</span> <span class="n">attribute</span> <span class="err">'</span><span class="n">on</span><span class="err">'</span> <span class="o">{</span><span class="n">input</span><span class="err">#</span><span class="n">agree</span><span class="o">}</span> </code></pre></div></div> <p>See <a href="https://github.com/selenide/selenide/issues/469">Issue 469</a> and <a href="https://github.com/selenide/selenide/pull/962">PR 962</a>.</p> <p><br /></p> <h1 id="upgraded-to-webdrivermanager362">Upgraded to WebDriverManager:3.6.2</h1> <p>It seems to have mostly fixes for Edge browser. <a href="https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md">Changelog is here</a>.</p> <p><br /></p> <h2 id="news">News</h2> <ul> <li>Boni García (author of WebDriverManager) created <a href="https://bonigarcia.github.io/selenium-jupiter">selenium-jupiter</a> - a wrapper for Selenide (+JUnit5 +Docker). Look ma, <em>a wrapper for a wrapper</em>!</li> <li>Comparision of Selenide and FluentLenium: <a href="https://testcraftsmanship.com/articles/2019/selenide_vs_fluentlenium_part1.html">Part 1</a>, <a href="https://testcraftsmanship.com/articles/2019/selenide_vs_fluentlenium_part2.html">Part 2</a></li> <li>Wow! Sergei Egorov (committer of TestContainers) created a true magic: <a href="https://github.com/bsideup/jabel">Jabel</a>. Now you can write code on Java13 and compile it to Java8 byte code.</li> </ul> <p><br /></p> <h2 id="conferences">Conferences</h2> <ul> <li>September, 20-21 - I will give two talks at <a href="http://qafest.com/en/">QA Fest</a> conference - Kyiv, Ukraine</li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2019/09/02/selenide-5.3.0/ https://selenide.org/2019/09/02/selenide-5.3.0 2019-09-02T00:00:00+00:00 Released Selenide 5.2.7 <p>Good summer everyone!</p> <p>We recently released several minor Selenide updates: 5.2.5-5.2.7.</p> <p>Let me speak from my heart why we needed them.</p> <p><br /></p> <h1 id="we-fixed-error-messages-when-running-selenideappium">We fixed error messages when running Selenide+Appium</h1> <p>Appium is a webdriver for mobile applications (<code class="language-plaintext highlighter-rouge">AndroidDriver</code>, <code class="language-plaintext highlighter-rouge">IOSDriver</code>). At a first glance, it seems to be a great idea: use the well-known Selenium WebDriver protocol for testing mobile. But many things that were “standard” and “reasonable” in web, work differently in mobile. Or do not work at all.</p> <blockquote> <p>Appium for Selenium is like Lobachevsky’s geometry for Euclidean geometry: everything is round and through the ass.</p> </blockquote> <p>That’s why Selenide could give illegal error messages in case of test failures. When trying to compose an error message, Selenide calls some “standard” methods which always worked in all web browsers: <code class="language-plaintext highlighter-rouge">$.getTagName()</code>, <code class="language-plaintext highlighter-rouge">$.isDisplayed()</code>, <code class="language-plaintext highlighter-rouge">executeJavascript()</code> etc. But which fail in Appium (either Android or iOS or both).</p> <p>To fix this issue, we had to add several <code class="language-plaintext highlighter-rouge">catch (NoSuchElementException | UnsupportedOperationException | UnsupportedCommandException | WebDriverException)</code> blocks which are essentially needed only because of Appium. We needed versions 5.2.6 and 5.2.7 just to add another <code class="language-plaintext highlighter-rouge">catch</code> for another corner case.</p> <p>Now Selenide works better for mobiles. Amen.</p> <p>See <a href="https://github.com/selenide/selenide/issues/496">issue 496 - Fix $.toString() in Appium</a></p> <p>NB! You can find <strong>examples of using Selenide for mobile</strong> <a href="https://github.com/selenide-examples/selenide-appium">on github</a>.</p> <p><br /></p> <h1 id="added-method-open-without-parameters">Added method <code class="language-plaintext highlighter-rouge">open()</code> without parameters</h1> <p>This method just opens an empty browser. Without a URL.</p> <p>It’s also needed for mobile. Selenide 5.+ requires that browser should be opened before any operations with web elements. But the traditional method <code class="language-plaintext highlighter-rouge">open(URL)</code> doesn’t work in Appium - you don’t have any URLs in mobile, you have applications.</p> <p>It’s a stupid situation, but we found an elegant solution, right? :)</p> <p>Thanks to <a href="https://github.com/yaroslav-orel">yaroslav-orel</a> for <a href="https://github.com/selenide/selenide/pull/956">PR 956</a>.</p> <p><br /></p> <h1 id="added-method-because-for-collections">Added method <code class="language-plaintext highlighter-rouge">because</code> for collections</h1> <p>As you know, to make error messages more readable, you can add a description to any condition. You don’t just say that the button is expected to be blue, but you also explain why <em>you think</em> that it should be blue:</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">"#login"</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">disabled</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#login"</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">disabled</span><span class="o">.</span><span class="na">because</span><span class="o">(</span><span class="s">"User entered a wrong password 3 times"</span><span class="o">));</span> </code></pre></div></div> <p>Now we have similar methods for 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="s">".cv"</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> <span class="err">$$</span><span class="o">(</span><span class="s">".cv"</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><span class="na">because</span><span class="o">(</span><span class="s">"Bob has two CVs and John has one."</span><span class="o">));</span> </code></pre></div></div> <p>Thanks to <a href="https://github.com/rkliuha">Roman Kliuha</a> for <a href="https://github.com/selenide/selenide/pull/904">PR 904</a></p> <p><br /></p> <h1 id="fixed-problem-with-open-inside-of-open">Fixed problem with <code class="language-plaintext highlighter-rouge">open</code> inside of <code class="language-plaintext highlighter-rouge">open</code></h1> <p>This is just an anecdotal case. You call method <code class="language-plaintext highlighter-rouge">open(url)</code> and get an error:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">IllegalStateException:</span> <span class="nc">No</span> <span class="n">webdriver</span> <span class="n">is</span> <span class="n">bound</span> <span class="n">to</span> <span class="n">current</span> <span class="nl">thread:</span> <span class="mi">19</span><span class="o">.</span> <span class="nc">You</span> <span class="n">need</span> <span class="n">to</span> <span class="n">call</span> <span class="nf">open</span><span class="o">(</span><span class="n">url</span><span class="o">)</span> <span class="n">first</span><span class="o">.</span> </code></pre></div></div> <p>Like, “you can’t call <code class="language-plaintext highlighter-rouge">open</code> because you have to call <code class="language-plaintext highlighter-rouge">open</code>”.</p> <p>After a small research we found that the problem was in combination Selenide+Allure.</p> <ol> <li>Selenide tried to open a browser</li> <li>Selenide failed to open it (e.g. could not find Chrome executable in PATH)</li> <li>Allure tried to add this even to its log</li> <li>Allure tried to make a screenshot</li> <li>Allure asked for screenshot from a “currently opened browser” and got an error.</li> </ol> <p>See fix in</p> <ul> <li>Selenide: <a href="https://github.com/selenide/selenide/issues/928">issue 928</a> and <a href="https://github.com/selenide/selenide/pull/958">PR 958</a></li> <li>Allure: <a href="https://github.com/allure-framework/allure-java/issues/379">issue 379</a> and <a href="https://github.com/allure-framework/allure-java/pull/380">PR 380</a></li> </ul> <p><br /></p> <h2 id="news">News</h2> <ul> <li>Video <a href="https://www.youtube.com/watch?v=dFQSOlOOoXE&amp;list=PLfazdZ9SzB9eDJIugtfH7KeVLLAP1pDLh">Antistatic</a> - Andrei Solntsev in <a href="https://devclub.ee">DevClub.ee</a>, Tallinn, 23.07.2019</li> <li>Blog post <a href="/2019/07/08/code-simplicity/">Code simplicity</a></li> </ul> <p><br /></p> <h2 id="conferences">Conferences</h2> <ul> <li>September, 20-21 - I will give two talks at <a href="http://qafest.com/en/">QA Fest</a> conference - Kyiv, Ukraine</li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2019/08/01/selenide-5.2.7/ https://selenide.org/2019/08/01/selenide-5.2.7 2019-08-01T00:00:00+00:00 Code simplicity <p>Let’s talk about simplicity of code.<br /> Probably all of you are agree that simple code is a good code. The problem is that we all understand “simplicity” differently.</p> <p>Let me show an example from one of site comments. So we can compare two variants and decide which one is simple.</p> <h3 id="a-goal">A goal</h3> <p>There is some “Gmail”-like list with checkboxes and titles. We need a page object allowing to find by title and click one or more checkboxes.</p> <h3 id="html-structure">HTML structure</h3> <p>is not really important, but it looks like this:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"box"</span><span class="nt">&gt;</span> <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"boxCheckbox"</span><span class="nt">&gt;</span> <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"checkbox"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/input&gt;</span> <span class="nt">&lt;/div&gt;</span> <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"boxLabel"</span><span class="nt">&gt;</span> Here is checkbox #1 <span class="nt">&lt;/div&gt;</span> <span class="nt">&lt;/div&gt;</span> <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"box"</span><span class="nt">&gt;</span> ... <span class="nt">&lt;/div&gt;</span> ... </code></pre></div></div> <p>here we have several <code class="language-plaintext highlighter-rouge">&lt;div class="box"&gt;</code>, each contains a pair <code class="language-plaintext highlighter-rouge">&lt;div class="boxCheckbox"&gt;</code> + <code class="language-plaintext highlighter-rouge">&lt;div class="boxLabel"&gt;</code>.</p> <h3 id="the-complex-code">The complex code</h3> <p>The following is a <strong>typical</strong> code that I saw so many-many times. I often think that this <strong>is</strong> nowadays automation.</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.WebElement</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">org.openqa.selenium.support.FindBy</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">java.util.ArrayList</span><span class="o">;</span> <span class="kn">import</span> <span class="nn">java.util.List</span><span class="o">;</span> <span class="kd">public</span> <span class="kd">class</span> <span class="nc">SeleniumPageObject</span> <span class="o">{</span> <span class="c1">// Search for element index in the list by title</span> <span class="kd">public</span> <span class="kd">static</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="nf">findListIndexesByTitle</span><span class="o">(</span><span class="nc">List</span><span class="o">&lt;</span><span class="nc">WebElement</span><span class="o">&gt;</span> <span class="n">elementList</span><span class="o">,</span> <span class="nc">String</span> <span class="nc">SearchText</span><span class="o">)</span> <span class="o">{</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">ints</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;();</span> <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">elementList</span><span class="o">.</span><span class="na">size</span><span class="o">();</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span> <span class="k">if</span> <span class="o">(</span><span class="n">elementList</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">getText</span><span class="o">().</span><span class="na">contains</span><span class="o">(</span><span class="nc">SearchText</span><span class="o">))</span> <span class="o">{</span> <span class="n">ints</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">i</span><span class="o">);</span> <span class="o">}</span> <span class="o">}</span> <span class="k">return</span> <span class="n">ints</span><span class="o">;</span> <span class="o">}</span> <span class="c1">// Buttons in the boxes</span> <span class="nd">@FindBy</span><span class="o">(</span><span class="n">xpath</span> <span class="o">=</span> <span class="s">"//div[@class='boxCheckbox']"</span><span class="o">)</span> <span class="kd">private</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">WebElement</span><span class="o">&gt;</span> <span class="n">selectCheckBoxesInBoxes</span><span class="o">;</span> <span class="c1">// Titles for boxes</span> <span class="nd">@FindBy</span><span class="o">(</span><span class="n">xpath</span> <span class="o">=</span> <span class="s">"//div[@class='boxLabel']"</span><span class="o">)</span> <span class="kd">private</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">WebElement</span><span class="o">&gt;</span> <span class="n">listOfTitlesInBoxes</span><span class="o">;</span> <span class="c1">// Select Box by title</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">selectBoxByTitle</span><span class="o">(</span><span class="nc">String</span> <span class="n">searchTitle</span><span class="o">)</span> <span class="o">{</span> <span class="kt">int</span> <span class="n">index</span> <span class="o">=</span> <span class="n">findListIndexesByTitle</span><span class="o">(</span><span class="n">listOfTitlesInBoxes</span><span class="o">,</span> <span class="n">searchTitle</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="n">selectBoxByIndex</span><span class="o">(</span><span class="n">index</span><span class="o">);</span> <span class="o">}</span> <span class="c1">// Select Box by index</span> <span class="kd">private</span> <span class="kt">void</span> <span class="nf">selectBoxByIndex</span><span class="o">(</span><span class="kt">int</span> <span class="n">elPosition</span><span class="o">)</span> <span class="o">{</span> <span class="n">selectCheckBoxesInBoxes</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">elPosition</span><span class="o">).</span><span class="na">click</span><span class="o">();</span> <span class="o">}</span> <span class="c1">// Select All Boxes by title</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">selectAllBoxesByTitle</span><span class="o">(</span><span class="nc">String</span> <span class="n">searchTitle</span><span class="o">)</span> <span class="o">{</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">ints</span> <span class="o">=</span> <span class="n">findListIndexesByTitle</span><span class="o">(</span><span class="n">listOfTitlesInBoxes</span><span class="o">,</span> <span class="n">searchTitle</span><span class="o">);</span> <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">ints</span><span class="o">.</span><span class="na">size</span><span class="o">();</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span> <span class="n">selectBoxByIndex</span><span class="o">(</span><span class="n">ints</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="o">}</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div></div> <p>You probably know that <a href="https://asolntsev.github.io/en/2010/05/02/javadoc/">comments in code are not needed</a>, and why <a href="https://asolntsev.github.io/ru/2016/07/09/true-page-object/"><code class="language-plaintext highlighter-rouge">@FindBy</code> doesn’t make things better</a> etc.</p> <p>Just compare these two code snippets.</p> <h3 id="the-simple-code">The simple code</h3> <p>I managed to convert the code above to Selenide:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">com.codeborne.selenide.SelenideElement</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">Condition</span><span class="o">.</span><span class="na">text</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">Selenide</span><span class="o">.</span><span class="err">$$</span><span class="o">;</span> <span class="kd">public</span> <span class="kd">class</span> <span class="nc">SelenidePageObject</span> <span class="o">{</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">selectBoxByTitle</span><span class="o">(</span><span class="nc">String</span> <span class="n">title</span><span class="o">)</span> <span class="o">{</span> <span class="n">selectBox</span><span class="o">(</span><span class="err">$$</span><span class="o">(</span><span class="s">".boxLabel"</span><span class="o">).</span><span class="na">findBy</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="n">title</span><span class="o">)));</span> <span class="o">}</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">selectAllBoxesByTitle</span><span class="o">(</span><span class="nc">String</span> <span class="n">searchTitle</span><span class="o">)</span> <span class="o">{</span> <span class="err">$$</span><span class="o">(</span><span class="s">".boxLabel"</span><span class="o">).</span><span class="na">filterBy</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="n">searchTitle</span><span class="o">)).</span><span class="na">forEach</span><span class="o">(</span><span class="k">this</span><span class="o">::</span><span class="n">selectBox</span><span class="o">);</span> <span class="o">}</span> <span class="kd">private</span> <span class="kt">void</span> <span class="nf">selectBox</span><span class="o">(</span><span class="nc">SelenideElement</span> <span class="n">boxLabel</span><span class="o">)</span> <span class="o">{</span> <span class="n">boxLabel</span><span class="o">.</span><span class="na">closest</span><span class="o">(</span><span class="s">".box"</span><span class="o">).</span><span class="na">find</span><span class="o">(</span><span class="s">".boxCheckbox"</span><span class="o">).</span><span class="na">click</span><span class="o">();</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div></div> <p>Don’t you think that’s SIMPLE?</p> <p>The latter variant is not ideal. But it’s much shorter and simpler. It’s easy to maintain. It’s easy to read. It’s easy to understand. It’s easy to modify. At the end, it’s easy to drop it off and write from the scratch.</p> <p>P.S. Have you noticed the trick? I said that I converted the code to Selenide, but the profit came mostly from simplifying selectors, removing unneeded code, using lambdas (read: contemporary language tools). You all can do it.</p> <p>Appreciate the simplicity, my friends!</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2019/07/08/code-simplicity/ https://selenide.org/2019/07/08/code-simplicity 2019-07-08T00:00:00+00:00 Released Selenide 5.2.4 <p>Good evening from the Summer!</p> <p>While people are celebrating Midsummer Day and Victory Day in Estonia, we are releasing Selenide 5.2.4.</p> <p>What’s new there?</p> <p><br /></p> <h1 id="we-fixed-proxy-on-localhost">We fixed proxy on localhost</h1> <p>As you know, Selenide can run its own embedded proxy server for some functions (file downloading, authorization, logging etc.). But last versions of popular browsers (Chrome72+ and Firefox 67+) started denying proxy to intercept requests to <code class="language-plaintext highlighter-rouge">localhost</code> (for some security reasons).</p> <p>That’s why downloading of file got broken for those who run AUT on <code class="language-plaintext highlighter-rouge">http://localhost:port</code> (like me).</p> <p>We had to dig into browser options and add tricky settings which allow proxy to intercept requests to <code class="language-plaintext highlighter-rouge">localhost</code>.</p> <p>See <a href="https://github.com/selenide/selenide/pull/950">PR 950</a>.</p> <p><br /></p> <h1 id="we-fixed-screenshooterextension-for-junit5">We fixed ScreenShooterExtension for JUnit5</h1> <p>As you know, when Selenide throws an error (as a rule, it’s a subclass of <code class="language-plaintext highlighter-rouge">UIAssertionError</code>), it always automatically takes a screenshot. In most cases it should be sufficient, but sometimes people want to use their own asserts (from JUnit, Hamcrest, AssertJ etc). Generally, Selenide cannot take screenshots in these cases - otherwise Selenide would depend on all those frameworks.</p> <p>But fortunately, Selenide has support for 3 most popular testing frameworks: <a href="https://github.com/selenide/selenide/blob/master/modules/junit4/src/main/java/com/codeborne/selenide/junit/ScreenShooter.java">JUnit4</a>, <a href="https://github.com/selenide/selenide/blob/master/statics/src/main/java/com/codeborne/selenide/junit5/ScreenShooterExtension.java">JUnit5</a>, <a href="https://github.com/selenide/selenide/blob/master/modules/testng/src/main/java/com/codeborne/selenide/testng/ScreenShooter.java">TestNG</a>.</p> <p>Recently we found a bug in <a href="https://github.com/selenide/selenide/blob/master/statics/src/main/java/com/codeborne/selenide/junit5/ScreenShooterExtension.java"><code class="language-plaintext highlighter-rouge">ScreenShooterExtension</code></a> for JUnit5. It took screenshots <em>only</em> for Selenide errors <code class="language-plaintext highlighter-rouge">UIAssertionError</code>. But should take for NON-selenide errors. So we <a href="https://github.com/selenide/selenide/commit/5414bc743469d0624e6f5">fixed it</a>.</p> <p><br /></p> <h1 id="we-improved-error-message-for-shouldhavetexts1-2-3">We improved error message for <code class="language-plaintext highlighter-rouge">$$.shouldHave(texts("1", "2", "3"))</code></h1> <p>Method <code class="language-plaintext highlighter-rouge">$$.shouldHave(texts(...))</code> allows to check texts of the whole collection of web elements. Method <code class="language-plaintext highlighter-rouge">$$.shouldHave(texts(...))</code> allows to check texts of the whole collection of web elements. For example, it’s very convenient for checking a row or a column of a table. But in some (rare) cases it could report correct, but unclear error message. We improved it.</p> <p>See <a href="https://github.com/selenide/selenide/issues/454">issue 454</a>.<br /> Thanks to <a href="https://github.com/xaknem">A.Smashentsev</a> for <a href="https://github.com/selenide/selenide/pull/944">PR 944</a>.</p> <p><br /></p> <h1 id="method-clickoffsetx-offsety-now-calculates-coordinates-for-the-center-of-element">Method <code class="language-plaintext highlighter-rouge">$.click(offsetX, offsetY)</code> now calculates coordinates for the CENTER of element</h1> <p>In addition to the “classical” method <code class="language-plaintext highlighter-rouge">$.click()</code>, Selenide has similar method <code class="language-plaintext highlighter-rouge">$.click(offsetX, offsetY)</code> for clicking with a shift. While “classical” <code class="language-plaintext highlighter-rouge">$.click()</code> clicks at the center of element, method <code class="language-plaintext highlighter-rouge">$.click(offsetX, offsetY)</code> allows to click at any point of the element.</p> <p>Here the difference comes: some browsers calculate the shift from center of element, while other - from left top corner. Even Selenium documentation for class <code class="language-plaintext highlighter-rouge">org.openqa.selenium.interactions.Actions</code> has a contradiction on this topic:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="cm">/** * Moves the mouse to an offset from the top-left corner of the element. */</span> <span class="kd">public</span> <span class="nc">Actions</span> <span class="nf">moveToElement</span><span class="o">(</span><span class="nc">WebElement</span> <span class="n">target</span><span class="o">,</span> <span class="kt">int</span> <span class="n">xOffset</span><span class="o">,</span> <span class="kt">int</span> <span class="n">yOffset</span><span class="o">)</span> <span class="o">{</span> <span class="o">...</span> <span class="c1">// Of course, this is the offset from the centre of the element. We have no idea what the width</span> <span class="c1">// and height are once we execute this method.</span> <span class="o">...</span> <span class="o">}</span> </code></pre></div></div> <p>Now we officially calculate shift from the <strong>center of element</strong>.</p> <p>See <a href="https://github.com/selenide/selenide/pull/950">PR 950</a>.</p> <p><br /></p> <h1 id="we-updated-dependencies">We updated dependencies</h1> <p>Some Selenide dependencies got updated:</p> <ul> <li>WebDriverManager 3.6.1</li> </ul> <p><br /></p> <h2 id="news">News</h2> <ul> <li><a href="https://www.testdevlab.com/blog/2019/05/testui-ui-test-automation-for-all-platforms-with-appium-and-selenide/">Framework TestUI on top of Appium and Selenide</a></li> <li>There was a <a href="https://dou.ua/calendar/27417">workshop “Selenide + Selenoid”</a> in Lviv, Ukraine. That’s cool!</li> <li>And a <a href="https://www.globallogic.com/ua/news/gl-ui-automation-cookbook-mykolaiv/">UI Automation Cookbook “Selenide + Allure”</a> in Mykolaiv, Ukraine. That’s also cool!</li> <li>An article from LambdaTest <a href="https://www.lambdatest.com/blog/selenium-testing-with-selenide-using-intellij-maven/">“Selenide+IntelliJ+Maven”</a></li> <li>An article in Japanese <a href="https://qiita.com/tatesuke/items/0bac60172e7cfd12aeb1">“Page Object with Selenide”</a> (?)</li> <li>Presentation in Japanese <a href="https://speakerdeck.com/shimashima35/example-of-e2e-automation-test-architecture-by-selenide-in-osaka">“E2E test automation infrastructure with DSL on Selenide”</a> (?)</li> <li>One more article in Japanese <a href="https://codezine.jp/article/detail/10335">“Selenoid + Selenide + Page objects”</a> (?)</li> <li>One more article in Japanese about <a href="https://qiita.com/shimashima35/items/0575ac5488edd6942d5a">recording a video while running Selenide tests</a> (?)</li> <li>Ambitious presentation <a href="https://www.slideshare.net/Bugraptors/selenide-vs-selenium-the-war-of-technologies">“Selenide vs. Selenium: The War Of Technologies”</a>. Let the battle begin!</li> </ul> <p><br /></p> <h1 id="conferences">Conferences</h1> <ul> <li>June, 27 - I will talk <a href="https://www.facebook.com/events/1335258949960597/">why static methods are bad</a> - DevClub, Tallinn, Estonia</li> <li>September, 20-21 - I will give two talks at <a href="http://qafest.com/en/">QA Fest</a> conference - Kyiv, Ukraine</li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2019/06/20/selenide-5.2.4/ https://selenide.org/2019/06/20/selenide-5.2.4 2019-06-20T00:00:00+00:00 Released Selenide 5.2.3 <p>On May, 7 we released Selenide 5.2.3 with small but backward incompatible changes.</p> <p>Don’t be afraid. Here is goes:</p> <p><br /></p> <h1 id="added-method-selenideloggerbeforeevent">Added method <code class="language-plaintext highlighter-rouge">SelenideLogger.beforeEvent()</code></h1> <p>Sometimes we need to log something BEFORE doing an action. For example, to write a log before any click. Selenide has interface <code class="language-plaintext highlighter-rouge">SelenideLogger</code>, but it always had only one method <code class="language-plaintext highlighter-rouge">onEvent()</code> which works AFTER an action. Now we added method <code class="language-plaintext highlighter-rouge">beforeEvent</code>. And renamed <code class="language-plaintext highlighter-rouge">onEvent</code> to <code class="language-plaintext highlighter-rouge">afterEvent</code> to make api cleaner.</p> <p>Thanks to <a href="https://github.com/pavelpp">pavelpp</a> for <a href="https://github.com/selenide/selenide/pull/927">PR 927</a>!</p> <p>NB! This change is backward incompatible.</p> <ol> <li>If you implemented <code class="language-plaintext highlighter-rouge">SelenideLogger</code> in your project, you need to rename/add method in your implementation.</li> <li>If you use library <code class="language-plaintext highlighter-rouge">selenide-allure</code>, you need to wait for its newer version with <a href="https://github.com/allure-framework/allure-java/pull/351">this PR</a>.</li> </ol> <p><br /></p> <h1 id="now-you-can-open-a-blank-page">Now you can open a blank page</h1> <p>Sometimes we need to open a blank page in test. For example, to stop all running Ajax requests from a previous test and start a new test from the scratch.</p> <p>Now you can use command <code class="language-plaintext highlighter-rouge">open("about:blank")</code> (before version 5.2.3, Selenide added <code class="language-plaintext highlighter-rouge">baseUrl</code> in the beginning of the address).</p> <p>See <a href="https://github.com/selenide/selenide/issues/914">issue 914</a> and <a href="https://github.com/selenide/selenide/pull/915">PR 915</a>.</p> <p><br /></p> <h1 id="refactoring-we-extracted-all-condition-implementations-to-separate-classes">Refactoring: we extracted all <code class="language-plaintext highlighter-rouge">Condition</code> implementations to separate classes</h1> <p>Just for your information. For most Selenide users, it doesn’t change anything.</p> <p>See <a href="https://github.com/selenide/selenide/pull/912">PR 912</a>.</p> <p><br /></p> <h1 id="updated-dependencies">Updated dependencies</h1> <ul> <li>one: WebDriverManager 3.4.0 (incl. support for Chrome 72, 73, 74)</li> <li>two: HtmlUnit 2.34.1</li> <li>three: HtmlUnitDriver 2.34.0</li> </ul> <h2 id="known-issues">Known issues</h2> <p>Two last versions of Chrome and Chromedriver (73 and 74) don’t work with BrowserMobProxy running on localhost. We don’t know why.</p> <p>It causes malfunctioning of downloading files and BasicAuth through proxy. Don’t you have the same problem?</p> <p>Currently we don’t have a better idea than just running tests on Chrome 71.</p> <p><br /></p> <h2 id="news">News</h2> <ul> <li>Wow, Selenide got to some TOP-5! <br /><a href="https://dev.to/arnabroychowdhury/top-5-java-test-frameworks-for-automation-in-2019-1528">Top 5 Java Test Frameworks For Automation In 2019</a></li> <li><a href="https://seleniumhq.github.io/docs/worst.html">Selenium worst practices</a> (officially, from the authors of Selenium!)</li> <li>Post about Selenide <strong>in Spanish</strong>! <br /> <a href="https://folderit.net/itech/selenide-framework-for-testing-automation/">Part 1</a> and <a href="https://folderit.net/itech/selenide-framework-for-testing-automation-segunda-parte/">part 2</a>.</li> <li>Post about Selenide+Allure: <a href="https://www.linkedin.com/pulse/adding-masala-selenide-test-automation-framework-amarasiri-/">Adding Masala to the Selenide Test Automation Framework with Allure</a>.</li> <li>One more tutorial for beginners from LambdaTest company: <br /> <a href="https://www.lambdatest.com/blog/selenium-testing-with-selenide-using-intellij-maven/">Selenium Tests Using Selenide, IntelliJ, And Maven</a></li> <li>Post about Selenide+Allure+Cucumber+Maven in Japanese: <a href="https://qiita.com/rolengrays/items/02030397fd2542021dd3">GUI test automation and result visualization</a>.</li> </ul> <p><br /></p> <h1 id="conferences">Conferences</h1> <ul> <li>I will present in Kiev, Ukraine at September, 20-21 on <a href="http://qafest.com/en/">QA Fest</a> conference. You are welcome!</li> <li>Wow. Hima Bindu Peteti <a href="https://www.youtube.com/watch?v=xpP_XYWqmQ0&amp;list=PL67l1VPxOnT5PZQ1r60wQoT2UPDk1of4z">talked about Selenide</a> on <a href="https://pbs.twimg.com/media/D480l1rUcAA63-Q.jpg:large">SauceCon conference</a> in Austin, Texas.</li> <li>She will also present Selenide in England on DevTEST Conference: <br /> <a href="https://www.softwaretestingnews.co.uk/products/devtest-conference-north/speakers/hima-bindu-peteti/">BDD with Selenide</a></li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2019/05/07/selenide-5.2.3/ https://selenide.org/2019/05/07/selenide-5.2.3 2019-05-07T00:00:00+00:00 Released Selenide 5.2.0 <p>Good evening!</p> <p>Now we are publishing press release of Selenide 5.2.0 which was released 19.02.2019.</p> <p>Let’s quickly read what was changed there, and move on to the next versions.</p> <p><br /></p> <h1 id="added-aliases-for-kotlin">Added aliases for Kotlin</h1> <p>Since symbols <code class="language-plaintext highlighter-rouge">$</code> and <code class="language-plaintext highlighter-rouge">$$</code> cannot be used as method name in Kotlin, using Selenide in Kotlin initially was not as pleasant as in Java. <a href="https://github.com/selenide-examples/kotlin/blob/master/src/test/kotlin/GoogleTest.kt">Here</a> you can see some examples of how it could be solved.</p> <p>After long discussions and researches, we decided to add simple aliases for Selenide methods <code class="language-plaintext highlighter-rouge">$</code> and <code class="language-plaintext highlighter-rouge">$$</code>: <code class="language-plaintext highlighter-rouge">element</code> and <code class="language-plaintext highlighter-rouge">elements</code>. It’s a little bit longer than <code class="language-plaintext highlighter-rouge">$</code>, but the result is human-readable:</p> <ul> <li><code class="language-plaintext highlighter-rouge">element(".header").shouldNot(exist)</code></li> <li><code class="language-plaintext highlighter-rouge">elements(".header").shouldHave(size(3))</code></li> </ul> <p>See <a href="https://github.com/selenide/selenide/issues/865">issue 865</a>.</p> <p>Thanks to <a href="https://github.com/jkromski">Jacek Kromski</a> for <a href="https://github.com/selenide/selenide/pull/870">PR 870</a>!</p> <p><br /></p> <h1 id="added-check-for-selected-text">Added check for selected text</h1> <p>Now you can check that an element has expected <em>selected text</em>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"textarea"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">selectedText</span><span class="o">(</span><span class="s">"oo ba"</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">"textarea"</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 bar"</span><span class="o">));</span> </code></pre></div></div> <p>See <a href="https://github.com/selenide/selenide/issues/766">issue 766</a>.</p> <p>Thanks to <a href="https://github.com/symonk">symonk</a> for <a href="https://github.com/selenide/selenide/pull/876">PR 876</a>!</p> <p><br /></p> <h1 id="improved-support-for-chromeoptionsargs-and-chromeoptionsprefs-system-properties">Improved support for <code class="language-plaintext highlighter-rouge">chromeoptions.args</code> and <code class="language-plaintext highlighter-rouge">chromeoptions.prefs</code> system properties</h1> <p>Actually, I am not sure if it’s a useful feature. Probably it’s easier to just implement <code class="language-plaintext highlighter-rouge">WebDriverProvider</code>. But still, we improved it.</p> <p>Thanks to <a href="https://github.com/vinogradoff">Alexei Vinogradov</a> for <a href="https://github.com/selenide/selenide/pull/883">PR 883</a>.</p> <p><br /></p> <h1 id="remove-an-old-hack-for-chrome-maximization">Remove an old hack for Chrome maximization</h1> <p>Older versions of Chrome driver could not maximize the browser window. That’s why Selenide had a special hack to maximize Chrome. Now it’s not needed anymore, and we removed the hack.</p> <p>See <a href="https://github.com/selenide/selenide/issues/838">issue 838</a> and <a href="https://github.com/selenide/selenide/pull/901">PR 901</a>.</p> <p><br /></p> <h2 id="news">News</h2> <ul> <li>Comparative analysis: <a href="https://speakerdeck.com/poohsunny/selenide-vs-geb">Selenide vs Geb</a></li> <li>Neodymium: a new framework based on Selenide from <a href="https://www.xceptance.com/en/company/">Xceptance</a> (Germany) <br /> <a href="https://dzone.com/articles/neodymium-an-open-source-framework-for-web-testing">Post 1</a> | <a href="https://blog.xceptance.com/2019/02/26/neodymium-an-open-source-framework-for-web-testing/">Post 2</a></li> <li>Akita: <a href="https://habr.com/ru/company/alfa/blog/350238/">testing framework based on Selenide</a> from Alfabank - one of biggest banks in Russia</li> <li>Post about <a href="https://habr.com/ru/company/alfa/blog/441674/">layout testing with Selenide</a> from Alfabank</li> <li>Post about BDD with Selenide: <a href="https://hackernoon.com/bdd-writing-a-test-suite-before-writing-code-6279e4cf4be6">BDD: Writing an Automated Test Suite isn’t Rocket Science</a></li> <li>And one more post about <a href="https://www.linkedin.com/pulse/eureka-integration-selenide-behavior-driven-amarasiri-/">BDD with Selenide+Cucumber</a></li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2019/02/19/selenide-5.2.0/ https://selenide.org/2019/02/19/selenide-5.2.0 2019-02-19T00:00:00+00:00 Released Selenide 5.1.1 <p>Good night!</p> <p>With a big lag and regret, we are publishing press release of Selenide 5.1.1 Let’s quickly read what was changed there, and move on to the next versions.</p> <h1 id="selenide-allows-clicking-on-transparent-elements">Selenide allows clicking on transparent elements</h1> <p>Until now, Selenide didn’t allow clicking elements with <code class="language-plaintext highlighter-rouge">opacity: 0</code>. It seemed reasonable because real user cannot click element which he cannot see. But we found that sometimes it’s useful - e.g. when there is a file upload field behind the transparent element.</p> <p>Now we don’t forbid it. :)</p> <p>See <a href="https://github.com/selenide/selenide/issues/201">issue 201</a></p> <p>Thanks to <a href="https://github.com/vinogradoff">Alexei Vinogradov</a> for <a href="https://github.com/selenide/selenide/pull/874">PR 874</a> and <a href="https://github.com/barancev">Alexei Barantsev</a> for patient explanations of how Selenium really works. :)</p> <p><br /></p> <h1 id="fixed-npe-when-custom-webdriver-is-run-without-proxy-but-user-asks-for-proxy">Fixed NPE when custom webdriver is run without proxy, but user asks for proxy</h1> <p>Now instead of <code class="language-plaintext highlighter-rouge">NullPointerException</code> you will see human-readable</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">IllegalStateException:</span> <span class="n">config</span><span class="o">.</span><span class="na">proxyEnabled</span> <span class="o">==</span> <span class="kc">true</span> <span class="n">but</span> <span class="n">proxy</span> <span class="n">server</span> <span class="n">is</span> <span class="n">not</span> <span class="n">started</span><span class="o">.</span> </code></pre></div></div> <p>See <a href="https://github.com/selenide/selenide/issues/878">issue 878</a> and <a href="https://github.com/selenide/selenide/pull/888">PR 888</a></p> <p><br /></p> <h1 id="now-you-can-switch-between-two-webdrivers-as-many-times-as-you-wish">Now you can switch between two webdrivers as many times as you wish</h1> <p>It worked correctly in Selenide 4.x and earlier, bug was broken in Selenide 5.0.0. Now we fixed it.</p> <p>See <a href="https://github.com/selenide/selenide/issues/867">issue 867</a> and <a href="https://github.com/selenide/selenide/pull/890">PR 890</a></p> <p><br /></p> <h1 id="selenide-generates-unique-folder-for-every-downloaded-file">Selenide generates unique folder for every downloaded file</h1> <p>Until now, Selenide used to download all files to folder <code class="language-plaintext highlighter-rouge">build/reports/tests</code> with their original names. It could cause a problem when two parallel tests tried to download files with the same name.</p> <p>Now Selenide will download every while to a unique folder <code class="language-plaintext highlighter-rouge">build/reports/UUID</code> (but still with its original name, because sometimes the file name is important).</p> <p>See <a href="https://github.com/selenide/selenide/issues/892">issue 892</a> and <a href="https://github.com/selenide/selenide/pull/893">PR 893</a>.</p> <p><br /></p> <h1 id="upgraded-to-selenium-java-314159">Upgraded to selenium-java 3.141.59</h1> <p>It’s so called “Pi” version of Selenium: 3.141.59 It seems to be the last Selenium version in 3.x line - the following is Selenium 4.0</p> <p>See selenium 3.141.* <a href="https://raw.githubusercontent.com/SeleniumHQ/selenium/master/java/CHANGELOG">Changelog</a></p> <h2 id="news">News</h2> <ul> <li>3 cool articles from Selenide committer <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> <ul> <li><a href="https://medium.com/@rosolko/simple-allure-2-configuration-for-gradle-8cd3810658dd">how to setup project with Gradle, JUnit5, Allure and Selenide</a>, and see <a href="https://github.com/rosolko/allure-gradle-configuration">code on </a></li> <li>How to speed up tests with <a href="https://medium.com/@rosolko/boost-you-autotests-with-fast-authorization-b3eee52ecc19">fast authorization</a></li> <li>How to speedup authorization <a href="https://medium.com/@rosolko/fast-authorization-level-local-storage-6c84e9b3cef1">with help of LocalStorage</a></li> </ul> </li> <li> <p>An old but good presentation <a href="https://www.slideshare.net/comaqa/page-object-with-selenide">Page object with selenide</a></p> </li> <li>The historical moment: somebody defended Master’s Thesis about Selenide:<br /> <a href="https://digi.lib.ttu.ee/i/?10612">“Development of Selenide Page Object class generator”</a></li> </ul> <p><br /> <a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2018/12/31/selenide-5.1.1/ https://selenide.org/2018/12/31/selenide-5.1.1 2018-12-31T00:00:00+00:00 Released Selenide 5.0.1 <p>Good morning! A month has passed since the release of Selenide 5.0.0. We haven’t got any bug reports. :)</p> <p>So, we have released Selenide 5.0.1 with minor fixes for old issues.</p> <h1 id="generate-random-file-name-for-downloaded-file">Generate random file name for downloaded file</h1> <p>As you know, Selenide has a method for direct file download by link:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">File</span> <span class="n">image</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://utdirect.utexas.edu/apps/pts/parking/citations/nlogon/images/6584836/"</span><span class="o">);</span> </code></pre></div></div> <p>It tries to get file name from http header or url. If neither is present (as in example above), it failed. Now it doesn’t fail anymore, but generates a random file name. Though I would consider it as the application bug.</p> <p>See <a href="https://github.com/selenide/selenide/issues/840">issue 840</a> and <a href="https://github.com/selenide/selenide/pull/856">PR 856</a>.</p> <p>Thanks to <a href="https://github.com/fyrewall77">David Phillips</a> for a solution idea.</p> <p><br /></p> <h1 id="fixed-indexoutofbounds-when-parent-element-is-not-found">Fixed <code class="language-plaintext highlighter-rouge">IndexOutOfBounds</code> when parent element is not found</h1> <p>This line caused <code class="language-plaintext highlighter-rouge">IndexOutOfBounds</code> before, but now it returns <code class="language-plaintext highlighter-rouge">false</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">"not-existing-locator"</span><span class="o">).</span><span class="na">first</span><span class="o">().</span><span class="err">$$</span><span class="o">(</span><span class="s">"locator"</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/issues/747">issue 747</a>.</p> <p>Thanks to <a href="https://github.com/Denysss">Denys Shynkarenko</a> for <a href="https://github.com/selenide/selenide/pull/837">PR 837</a>.</p> <p><br /></p> <h1 id="fixed-classcastexception-in-method-toarray">Fixed <code class="language-plaintext highlighter-rouge">ClassCastException</code> in method <code class="language-plaintext highlighter-rouge">$$.toArray()</code></h1> <p>This code caused <code class="language-plaintext highlighter-rouge">ClassCastException</code> before:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">List</span><span class="o">&lt;</span><span class="nc">SelenideElement</span><span class="o">&gt;</span> <span class="n">selenideElements</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;();</span> <span class="n">selenideElements</span><span class="o">.</span><span class="na">addAll</span><span class="o">(</span><span class="err">$$</span><span class="o">(</span><span class="s">"#table1 td"</span><span class="o">));</span> </code></pre></div></div> <p>I don’t even want to know why somebody should need such code in tests… But well, we had to fix it, and we fixed it.</p> <p>See <a href="https://github.com/selenide/selenide/issues/844">issue 844</a>.</p> <p>Thanks to <a href="https://github.com/BorisOsipov">Boris Osipov</a> for <a href="https://github.com/selenide/selenide/pull/847">PR 847</a>.</p> <p><br /></p> <h1 id="added-support-for-chrome-70">Added support for chrome 70</h1> <p>Starting from version 3.0, WebDriverManager became flaky. It contains file <code class="language-plaintext highlighter-rouge">versions.properties</code> which matches versions of webdrivers and browsers. But WDM gets updates much less frequently than browsers and webdrivers. Naturally, every time when new version of Firefox or Chrome gets released, WDM doesn’t support it.</p> <p>By now, we added own version of <code class="language-plaintext highlighter-rouge">versions.properties</code> to Selenide. Selenide is updated more frequently than WDM. :)</p> <p>We already added chrome70=2.42 and firefox62 there. We need your ideas how to deal with it in future. Feel free to share your thoughts!</p> <p>See <a href="https://github.com/selenide/selenide/pull/855">PR 855</a>.</p> <p><br /></p> <h1 id="upgraded-to-selenium-java-31415">Upgraded to selenium-java 3.141.5</h1> <p><a href="https://raw.githubusercontent.com/SeleniumHQ/selenium/master/java/CHANGELOG">Changelog</a> of selenium 3.141.*</p> <p><br /></p> <h2 id="selenide-download-statistics">Selenide download statistics</h2> <p>Downloads count continues growing. We crossed the line 40800 downloads per month!</p> <center> <img src="/images/2018/10/selenide-downloads.png" width="800" /> </center> <p><br /></p> <h2 id="conferences">Conferences</h2> <p>If you haven’t been yet, I recommend to go to <a href="https://heisenbug-moscow.ru/2018/msk/people/">Heisenbug conference</a> in Moscow (December 2019).</p> <p>It’s a really great conference. Believe me, I have been there last year.</p> <p><br /> <a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2018/11/07/selenide-5.0.1/ https://selenide.org/2018/11/07/selenide-5.0.1 2018-11-07T00:00:00+00:00 Released Selenide 5.0.0 <p>It finally happened! We released a major Selenide version 5.0.0</p> <p>The biggest change in Selenide 5.0.0 is a global refactoring. This is internal change. It should not (almost) affect you. For those who are interested - I am going to share refactoring details in a separate post.</p> <p>What changes are waiting you in Selenide 5.0.0?</p> <h1 id="you-can-open-two-browsers-in-test">You can open two browsers in test</h1> <p>First of all: <em>don’t use this feature</em>!<br /> In most cases, it’s a <strong>bad idea</strong> to open two or three browsers in a test.</p> <blockquote> <p>Typically people want it to test multi-user scenarios. Something like that:</p> <ol> <li>In one browser, open an admin panel and modify some setting</li> <li>In other browser, open a user page and verify that the setting has been applied correctly.</li> </ol> <p>The right solution in this case is to test admin panel separately, and user page separately. Don’t mix different tests into one. When you need to setup environment for test (incl. changing any settings or emulating input from other user), you can use whatever tools (rest call, insert into database etc) but <strong>not through UI</strong>. You are testing UI - it means that <strong>you are not allowed to trust UI</strong>.</p> </blockquote> <p>If you still want to use bad practice, the API looks like this:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">SelenideDriver</span> <span class="n">browser1</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">SelenideDriver</span><span class="o">();</span> <span class="nc">SelenideDriver</span> <span class="n">browser2</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">SelenideDriver</span><span class="o">();</span> <span class="n">browser1</span><span class="o">.</span><span class="na">open</span><span class="o">(</span><span class="s">"https://google.com"</span><span class="o">);</span> <span class="n">browser2</span><span class="o">.</span><span class="na">open</span><span class="o">(</span><span class="s">"http://yandex.ru"</span><span class="o">);</span> <span class="n">browser1</span><span class="o">.</span><span class="err">$</span><span class="o">(</span><span class="n">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">"Google"</span><span class="o">));</span> <span class="n">browser2</span><span class="o">.</span><span class="err">$</span><span class="o">(</span><span class="n">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">"Yandeks"</span><span class="o">));</span> </code></pre></div></div> <p>See actual example in <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/SelenideDriverITest.java">Selenide own tests</a></p> <p>See <a href="https://github.com/selenide/selenide/issues/354">issue 354</a> and <a href="https://github.com/selenide/selenide/pull/801">PR 801</a></p> <p>My thanks go to people who played an important role in this long-running refactoring:</p> <ul> <li><a href="https://github.com/yashaka">Iakiv Kramarenko</a> for the initial idea,</li> <li><a href="https://github.com/barancev">Alexei Barantsev</a> for constructive and convincing arguments,</li> <li><a href="https://github.com/rosolko">Aliaksandr Rasolka</a> for moral support and idea generation.</li> </ul> <p>NB! Old good <code class="language-plaintext highlighter-rouge">open</code>, <code class="language-plaintext highlighter-rouge">$</code>, <code class="language-plaintext highlighter-rouge">$$</code> still work, and I still recommend to use them. They do use <code class="language-plaintext highlighter-rouge">new SelenideDriver()</code> inside, but they correctly store and destroy it. You just don’t need to reinvent the wheel and solve the same problems again and again.</p> <p>Let me repeat myself: two browsers in one test is most probably a <strong>BAD PRACTICE</strong>!</p> <p><br /></p> <h1 id="now-selenide-uses-chrome-by-default">Now Selenide uses Chrome by default</h1> <p>Many years ago, we chose Firefox as a default browser because it was the only browser which did not require installation of a webdriver binary. Nowadays this argument is not valid because 1) Firefox now also requires installation of geckodriver, and 2) Selenide can install webdrivers automatically.</p> <p>From our experience, Chrome is faster and more stable. That’s why now is Chrome Era.</p> <p>See <a href="https://github.com/selenide/selenide/issues/811">issue 811</a> – thanks to <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/812">PR 812</a></p> <p><br /></p> <h1 id="selenide-does-not-maximize-browser-by-default">Selenide does <em>not</em> maximize browser by default</h1> <p>At the beginning it seemed to be a good idea to open browser to the full screen size. It should make tests stable: more elements fit to the screen. Many people still think this way.</p> <p>Actually it makes tests flaky because tests result depends on screen size which is a random uncontrollable variable. Our new recommendation to set browser size explicitly to the minimal size supported by your application.</p> <p>Selenide 5.0.0 by default sets browsers size to <code class="language-plaintext highlighter-rouge">1366x768</code> because it is worlds’ most popular resolution by the moment. As usually, you can redefine it as any other setting.</p> <p>See <a href="https://github.com/selenide/selenide/issues/810">issue 810</a> – thanks to <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/812">PR 812</a></p> <p><br /></p> <h1 id="selenide-doesnt-open-a-browser-automatically">Selenide doesn’t open a browser automatically</h1> <p>Methods <code class="language-plaintext highlighter-rouge">$</code> and <code class="language-plaintext highlighter-rouge">$$</code> now throw an exception if browser is not opened yet (or is already closed). The right way is to open a browser first (by calling <code class="language-plaintext highlighter-rouge">open(url)</code>) and then search elements (<code class="language-plaintext highlighter-rouge">$</code>, <code class="language-plaintext highlighter-rouge">$$</code> etc).</p> <p>Before this release, methods <code class="language-plaintext highlighter-rouge">$</code> and <code class="language-plaintext highlighter-rouge">$$</code> opened a new browser automatically if it was not open yet. This behaviour could be unexpected sometimes. For example, people got Firefox when they expected Chrome. Or got two browsers when they expected one. Yes, it was a bug in tests, but now Selenide helps to find it faster.</p> <blockquote> <p>There are known cases when tests started failing after upgrade to Selenide 5.0.0 for two reasons:</p> <ol> <li>Page object fields were declared static, and browser was closed after every test. Static fields were initialized only once. Every following test didn’t re-initialize them, but got from a previous test <code class="language-plaintext highlighter-rouge">SelenideElement</code> instances containing a reference to (already closed) webdriver. Solution: make page object fields non-static. Static is evil.</li> <li>Test class fields (in case of TestNG) were initialized in field declaration, not in <code class="language-plaintext highlighter-rouge">setUp</code> method. That’s why I love JUnit. Happy JUnit users can afford such a luxury: <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">MyTest</span> <span class="o">{</span> <span class="nc">SelenideElement</span> <span class="n">header</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"h1"</span><span class="o">);</span> <span class="o">}</span> </code></pre></div> </div> <p>But poor TestNG users are forced to move initialization to <code class="language-plaintext highlighter-rouge">@Before</code>-like methods:</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">MyTest</span> <span class="o">{</span> <span class="nc">SelenideElement</span> <span class="n">header</span><span class="o">;</span> <span class="nd">@BeforeEach</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setUp</span><span class="o">()</span> <span class="o">{</span> <span class="n">header</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"h1"</span><span class="o">);</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div> </div> <p>Looks ugly, right? My advice: forget TestNG. JUnit rules.</p> </li> </ol> </blockquote> <p>See <a href="https://github.com/selenide/selenide/issues/809">issue 809</a></p> <p><br /></p> <h1 id="cleaned-up-unused-settings-and-features">Cleaned up unused settings and features</h1> <p>See <a href="https://github.com/selenide/selenide/issues/806">issue 806</a> – thanks to <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/812">PR 812</a></p> <p>Among other changes, we removed the following settings:</p> <ul> <li><code class="language-plaintext highlighter-rouge">browser</code> (use <code class="language-plaintext highlighter-rouge">selenide.browser</code> instead)</li> <li><code class="language-plaintext highlighter-rouge">remote</code> (use <code class="language-plaintext highlighter-rouge">selenide.remote</code> instead)</li> <li><code class="language-plaintext highlighter-rouge">selenide.browser-size</code> (use <code class="language-plaintext highlighter-rouge">selenide.browserSize</code> instead)</li> <li><code class="language-plaintext highlighter-rouge">selenide.browser.version</code> (use <code class="language-plaintext highlighter-rouge">selenide.browserVersion</code> instead)</li> <li><code class="language-plaintext highlighter-rouge">browser.version</code> (use <code class="language-plaintext highlighter-rouge">selenide.browserVersion</code> instead)</li> <li><code class="language-plaintext highlighter-rouge">selenide.start-maximized</code> (use <code class="language-plaintext highlighter-rouge">selenide.startMaximized</code> instead)</li> <li><code class="language-plaintext highlighter-rouge">selenide.chrome.switches</code> (use <code class="language-plaintext highlighter-rouge">selenide.chromeSwitches</code> instead)</li> <li><code class="language-plaintext highlighter-rouge">chrome.switches</code> (use <code class="language-plaintext highlighter-rouge">selenide.chromeSwitches</code> instead)</li> <li><code class="language-plaintext highlighter-rouge">selenide.page-load-strategy</code> (use <code class="language-plaintext highlighter-rouge">selenide.pageLoadStrategy</code> instead)</li> <li><code class="language-plaintext highlighter-rouge">selenide.click-via-js</code> (use <code class="language-plaintext highlighter-rouge">selenide.clickViaJs</code> instead)</li> <li><code class="language-plaintext highlighter-rouge">selenide.reports</code> (use <code class="language-plaintext highlighter-rouge">selenide.reportsFolder</code> instead)</li> </ul> <p><br /></p> <h1 id="removed-junit5-api-api-dependency">Removed <code class="language-plaintext highlighter-rouge">junit5-api</code> api dependency</h1> <p>Selenide transitively pulled <code class="language-plaintext highlighter-rouge">junit5-api</code> dependency to your project, even if you don’t use JUnit5. Apparently you don’t want it. Now it doesn’t.</p> <p>If you use JUnit5 and some classes disappeared from classpath after upgrade, you will need to add JUnit5 dependency explicitly: <code class="language-plaintext highlighter-rouge">"org.junit.jupiter:junit-jupiter-api:5.3.1"</code>.</p> <p><br /></p> <h1 id="and-minor-changes">And minor changes:</h1> <ul> <li>Classes <code class="language-plaintext highlighter-rouge">AssertionMode</code>, <code class="language-plaintext highlighter-rouge">SelectorMode</code>, <code class="language-plaintext highlighter-rouge">FileDownloadMode</code> moved from class <code class="language-plaintext highlighter-rouge">Configuration</code> to package <code class="language-plaintext highlighter-rouge">com.codeborne.selenide</code>.</li> <li>Now Selenide throws <code class="language-plaintext highlighter-rouge">ElementIsNotClickableException</code> instead of <code class="language-plaintext highlighter-rouge">ElementNotFoundException</code> (if element could not be clicked because it was covered by another element).</li> <li>Selenide throws error if <code class="language-plaintext highlighter-rouge">Configuration.fileDownload == PROXY</code> but <code class="language-plaintext highlighter-rouge">Configuration.proxyEnabled == false</code>. You will need to explicitly set <code class="language-plaintext highlighter-rouge">Configuration.proxyEnabled=true</code> to download files via proxy.</li> <li><a href="https://github.com/selenide/selenide/issues/817">817</a> fix “FirefoxDriverFactory overwrites Firefox profile provided by Configuration” – thanks to <a href="https://github.com/BorisOsipov">Boris Osipov</a> for <a href="https://github.com/selenide/selenide/pull/821">PR 821</a></li> <li>bugfix: method Selenide.download() should not fail if there is no opened browser yet</li> <li><a href="https://github.com/selenide/selenide/pull/825">825</a> Upgraded WebDriverManager to 3.0.0 (again)</li> <li><a href="https://github.com/selenide/selenide/pull/825">825</a> Created a workaround for WebDriverManager, so that it doesn’t call github api too often (getting 403 error)</li> <li><a href="https://github.com/selenide/selenide/pull/832">832</a> Added support for screenshots outside of “user.dir” in CI server – thanks <a href="https://github.com/admizh">Alex Yu</a></li> </ul> <p><br /></p> <h1 id="technical-changes-which-probably-will-not-affect-you">Technical changes (which probably will not affect you)</h1> <ul> <li>Upgraded to htmlunitdriver 2.33.0</li> <li>Moved constants <code class="language-plaintext highlighter-rouge">IE</code>, <code class="language-plaintext highlighter-rouge">FIREFOX</code> etc. from class <code class="language-plaintext highlighter-rouge">WebDriverRunner</code> to its parent class <code class="language-plaintext highlighter-rouge">Browsers</code></li> <li>Moved classes <code class="language-plaintext highlighter-rouge">Selenide</code>, <code class="language-plaintext highlighter-rouge">WebDriverRunner</code>, <code class="language-plaintext highlighter-rouge">Configuration</code> to subfolder <a href="https://github.com/selenide/selenide/tree/master/statics">statics</a>.</li> <li>Moved default settings initialization from <a href="https://github.com/selenide/selenide/blob/master/statics/src/main/java/com/codeborne/selenide/Configuration.java">Configuration</a> to <a href="https://github.com/selenide/selenide/blob/master/src/main/java/com/codeborne/selenide/SelenideConfig.java">SelenideConfig</a>.</li> <li>when waiting for a condition, catch explicitly only needed exceptions instead of <code class="language-plaintext highlighter-rouge">Throwable</code> which is too generic. It does not make sense to wait for 4 seconds in case of IllegalStateException, FileNotFoundException etc.</li> </ul> <p><br /></p> <h2 id="news">News</h2> <ul> <li>We moved Selenide project to a dedicated github organisation: <a href="https://github.com/selenide">github.com/selenide</a></li> <li>Just a reminder: selenide usage examples with different frameworks are located in a separate organisation <a href="https://github.com/selenide-examples">github.com/selenide-examples</a></li> <li>We created a <a href="https://github.com/selenide/selenide-gradle-template">Selenide project template for Gradle</a></li> <li>A video from my DevCon 2018 speech was published: <a href="https://www.youtube.com/watch?v=o6AEfW39f0Y">Selenide: fall in love after 15 slides</a></li> <li>Boring comparision: <a href="https://www.bugraptors.com/selenide-vs-selenium/">Selenide vs. Selenium: The War Of Technologies!!!</a></li> <li>16.10.2018, Krakow, Agile &amp; Automation Days - <a href="http://aadays.pl/speakers/alexei-vinogradov/">Selenide master class</a>, Aleksei Vinogradov</li> <li>7.11.2018, Belgrade, Test Conference - <a href="https://bg-testconference.rs/agenda#/sessions/rapid-ui-test-automation-with-selenide">Rapid UI-Test automation with Selenide</a>, Aleksei Vinogradov</li> <li>18.10.2018, Moscow, anonymous automation engineers meetup - <a href="https://www.meetup.com/%D0%9E%D0%B1%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%BE-%D0%B0%D0%BD%D0%BE%D0%BD%D0%B8%D0%BC%D0%BD%D1%8B%D1%85-%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D1%89%D0%B8%D0%BA%D0%BE%D0%B2/events/255547063/">Configuration in tests. Gradle, Java, Selenide</a>, Boris Osyanin</li> <li>Tomorrow there is a meetup in America - <a href="https://www.meetup.com/NOVA-Software-Quality-Engineering-and-Automation-Meetup/events/254691657/">BDD with Selenide</a> - 16.10.2018, Reston, VA <blockquote> <p>Selenide is an open-source library that can make a <strong>huge impact</strong> on and accelerate software delivery by introducing a concise API, shorter expressions, and many other capabilities.</p> </blockquote> </li> </ul> <h2 id="we-get-7-years-old">We get 7 years old!</h2> <p>Time does go on. Could we imagine that? Selenide gets 7 at October, 25. Now it’s funny to look at the first commits:</p> <center> <img src="/images/2018/10/selenide-first-commits.png" width="800" /> </center> <p><br /></p> <h1 id="how-your-upgrade-went">How your upgrade went?</h1> <p>Share your experience, register <a href="https://github.com/selenide/selenide/issues">github issues</a>, discuss your problems in <a href="https://testers.io/messages/selenide">slack</a> and <a href="https://gitter.im/codeborne/selenide">gitter</a>.</p> <p><br /> <a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2018/10/10/selenide-5.0.0/ https://selenide.org/2018/10/10/selenide-5.0.0 2018-10-10T00:00:00+00:00 Released Selenide 4.14.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! - 21 years ago. And since we are still alive, we decided to release Selenide 4.14.0 at this historical day.</p> <p>There is not so much changes, and they are mostly about Selenide proxy server.</p> <p><br /></p> <h1 id="we-implemented-basicauth-through-proxy">We implemented BasicAuth through proxy</h1> <p>Test servers are often password-protected (so called BasicAuth). (I really don’t understand why it’s needed: they are <em>in intranet</em> anyway! But nothing to do, people do it.)</p> <p>Until today, Selenide could only bypass BasicAuth by adding <code class="language-plaintext highlighter-rouge">username:password@</code> to URL. But folks say that it doesn’t always work in some browsers. Now we implemented BasicAuth through selenide proxy server instead of URL. Roughly speaking, Selenide adds a http header <code class="language-plaintext highlighter-rouge">Authorization: Basic foobar</code> to every request from browser to application. This way definitely works in all browsers. So go enable proxy in your tests (see next chapter).</p> <p>See <a href="https://github.com/selenide/selenide/issues/784">issue 784</a> – thanks to <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/785">PR 785</a></p> <p><br /></p> <h1 id="we-added-a-dedicated-setting-to-enabledisable-proxy-server">We added a dedicated setting to enable/disable proxy server</h1> <p>As you know, Selenide can run its own built-in proxy server which tracks requests between browser and application under test. Initially, it was used only for downloading files. That’s why Selenide didn’t have any special settings for proxy - it was be enabled just by setting <code class="language-plaintext highlighter-rouge">Configuration.fileDownload == PROXY</code>.</p> <p>Now proxy server is used for more different features (see previous chapter), and more is coming.</p> <p>That’s why we added a dedicated setting to enable/disable proxy server:</p> <ul> <li><code class="language-plaintext highlighter-rouge">Configuration.proxyEnabled = true | false</code> (default value: false)</li> </ul> <p>Let me explain why <code class="language-plaintext highlighter-rouge">false</code> is by default. I personally recommend to enable proxy server. It’s a good guy. It allows us features that are not possible with plain selenium.</p> <p>Proxy will not work only in one case. When tests and browser are run on different machines, and the “tests machine” is not visible from the “browser machine”. I hope it’s not the case for most of you. I don’t really understand why people need to create barriers between test servers <em>in intranet</em>. But well, bloody enterprise do it, you know… :( That’s why we put <code class="language-plaintext highlighter-rouge">proxyEnabled</code> to false by default.</p> <p>There are couple of settings for fine-tuning proxy server (not needed for most of you):</p> <ul> <li><code class="language-plaintext highlighter-rouge">Configuration.proxyHost</code> <br />Default value: <code class="language-plaintext highlighter-rouge">""</code> (Selenide will automatically put IP or host of local machine)</li> <li><code class="language-plaintext highlighter-rouge">Configuration.proxyPort</code> <br />Default value: <code class="language-plaintext highlighter-rouge">0</code> (Selenide will automatically pick a random free port on local machine)</li> </ul> <p>See <a href="https://github.com/selenide/selenide/issues/788">issue 788</a> and <a href="https://github.com/selenide/selenide/pull/791">PR 791</a></p> <p><br /></p> <h1 id="we-removed-an-old-ie-specific-hack">We removed an old IE-specific hack</h1> <p>When running tests in IE, Selenide always added a <code class="language-plaintext highlighter-rouge">?timestamp=somerandomnumbers</code> parameter to every URL. It was a hack to force IE reload pages. It was a long time ago. At that time, it seemed that IE sometimes didn’t reload content on click, but got it from cache.</p> <p>Now I think that the reason was somewhere else, not in IE. And this hack is not really needed. So we removed it.</p> <p>See <a href="https://github.com/selenide/selenide/issues/789">issue 789</a> and <a href="https://github.com/selenide/selenide/pull/790">PR 790</a></p> <h2 id="news">News</h2> <p>We got updated download statistics for Selenide. It’s awesome! We achieved 37000+ downloads per month!</p> <center> <img src="/images/2018/08/selenide.downloads.png" width="800" /> </center> <h2 id="what-do-you-think">What do you think?</h2> <p>Feel free to share your ideas how we can use proxy server. Let’s discuss it!</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2018/08/29/selenide-4.14.0/ https://selenide.org/2018/08/29/selenide-4.14.0 2018-08-29T00:00:00+00:00 Released Selenide 4.13.0 <p>Hi all!</p> <p>On August 20, Estonia marks a unique holiday - the Day of Restoration of Independence. 08/20/1991 Estonia regained its independence. Right now, outside the window, a many-thousands-strong choir sings patriotic songs and thunders salute.</p> <p>And I am rolling out to the sounds of the salute … Selenide 4.13.0</p> <p>There were more changes than it seemed to me. :)</p> <p><br /></p> <h1 id="added-method-lastchild">Added method <code class="language-plaintext highlighter-rouge">$.lastChild()</code></h1> <p>It finds the last child element of given element. Like <code class="language-plaintext highlighter-rouge">$("table").lastChild().shouldHave(cssClass("lastRow"));</code></p> <p>See <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/LastChildTest.java">examples in Selenide tests</a></p> <p>Thanks to <a href="https://github.com/symonk">SymonK</a> for <a href="https://github.com/selenide/selenide/pull/771">PR 771</a></p> <p><br /></p> <h1 id="added-collection-checks-with-custom-timeout">Added collection checks with custom timeout</h1> <p>As you know, Selenide always had method <code class="language-plaintext highlighter-rouge">$.waitUntil(condition, timeout)</code> for waiting for some event with non-standard timeout. Now we added similar method for collections. Though, we decided not to name it <code class="language-plaintext highlighter-rouge">waitUntil</code>, because this name doesn’t match well with condition names: <code class="language-plaintext highlighter-rouge">$$.waitUntil(texts("a", "b", "c"))</code> doesn’t sound well in English. Instead, we use the same name as before:</p> <ul> <li><code class="language-plaintext highlighter-rouge">$$.shouldBe(empty, 9000)</code></li> <li><code class="language-plaintext highlighter-rouge">$$.shouldHave(size(4), 9000)</code></li> </ul> <p>See more examples <a href="https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/CollectionWaitTest.java">in Selenide tests</a>.</p> <p>See <a href="https://github.com/selenide/selenide/issues/601">issue 601</a> and <a href="https://github.com/selenide/selenide/pull/781">PR 781</a></p> <p><br /></p> <h1 id="added-method-selenidedownloadurl">Added method <code class="language-plaintext highlighter-rouge">Selenide.download(url)</code></h1> <p>It downloads a file by direct link. But downloads as it was downloaded by browser. Technically speaking, Selenide performs Http GET request with your provided URL, but adds cookies and <code class="language-plaintext highlighter-rouge">User-Agent</code> header from currently opened webdriver.</p> <p>See more examples <a href="https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/DirectFileDownloadTest.java">in Selenide tests</a>.</p> <p>See <a href="https://github.com/selenide/selenide/pull/782">PR 782</a></p> <p><br /></p> <h1 id="upgraded-to-selenium-3140">Upgraded to Selenium 3.14.0</h1> <p>Just in case, I have to mention that <code class="language-plaintext highlighter-rouge">SelenideElement</code> doesn’t implement the following deprecated interfaces anymore:</p> <ul> <li><code class="language-plaintext highlighter-rouge">FindsByLinkText</code></li> <li><code class="language-plaintext highlighter-rouge">FindsById</code></li> <li><code class="language-plaintext highlighter-rouge">FindsByName</code></li> <li><code class="language-plaintext highlighter-rouge">FindsByTagName</code></li> <li><code class="language-plaintext highlighter-rouge">FindsByClassName</code></li> <li><code class="language-plaintext highlighter-rouge">FindsByCssSelector</code></li> <li><code class="language-plaintext highlighter-rouge">FindsByXPath</code></li> <li><code class="language-plaintext highlighter-rouge">HasIdentity</code></li> </ul> <p>I believe it will not affect you. Just in case.</p> <p>See <a href="https://github.com/selenide/selenide/pull/773">PR 773</a></p> <p><br /></p> <h1 id="method-switchtoalert-now-throws-noalertpresentexception">Method <code class="language-plaintext highlighter-rouge">switchTo().alert()</code> now throws <code class="language-plaintext highlighter-rouge">NoAlertPresentException</code></h1> <p>… instead of<code class="language-plaintext highlighter-rouge">TimeoutException</code></p> <p>See <a href="https://github.com/selenide/selenide/issues/273">issue 273</a> – thanks to <a href="https://github.com/tsukakei">Keita Tsukamoto</a> for <a href="https://github.com/selenide/selenide/pull/774">PR 774</a></p> <p><br /></p> <h1 id="fixed-error-message-from-selectoptionbyvalue">Fixed error message from <code class="language-plaintext highlighter-rouge">$.selectOptionByValue()</code></h1> <p>See <a href="https://github.com/selenide/selenide/issues/709">issue 709</a> – thanks to <a href="https://github.com/tsukakei">Keita Tsukamoto</a> for <a href="https://github.com/selenide/selenide/pull/780">PR 780</a></p> <p><br /></p> <h1 id="fixed-name-of-downloaded-file">Fixed name of downloaded file</h1> <p>See <a href="https://github.com/selenide/selenide/issues/734">issue 734</a> – thanks to <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/768">PR 768</a></p> <p><br /></p> <h1 id="upgraded-to-webdrivermanager-225">Upgraded to WebdriverManager 2.2.5</h1> <p>See <a href="https://github.com/selenide/selenide/pull/783">PR 783</a> and <a href="https://github.com/bonigarcia/webdrivermanager/blob/master/changelog">WebdriverManager changelog</a></p> <p><br /></p> <h1 id="upgraded-to-htmlunit-2321">Upgraded to HtmlUnit 2.32.1</h1> <p>See <a href="https://github.com/selenide/selenide/pull/775">PR 775</a></p> <p><br /></p> <h1 id="fixed-selenide-own-tests-firefox">Fixed Selenide own tests Firefox</h1> <p>Probably you remember the historical moment when webdriver for Firefox already didn’t work, but Geckodriver (aka Marionette) didn’t work yet. At that moment we had to “temporarily” disable Selenide own tests in Firefox. And recently we discovered that there have been disables for last N years :(</p> <p>Now we finally enabled them back and fixed. We had to fix quite a lot of things… We probably even fixed some Firefox-specific bugs. :)</p> <p>See <a href="https://github.com/selenide/selenide/pull/778">PR 778</a></p> <p><br /></p> <h2 id="news">News</h2> <ul> <li> <p>A great fragment of a phrase in a chat:</p> <blockquote> <p>I use Java not only for being Java, but also for existing sweeties: Selenide, RestAssured etc.</p> </blockquote> </li> <li>We discovered two new frameworks, both powered by Selenide: <ul> <li><a href="https://github.com/sysgears/selenium-automation-bundle">Selenium Automation Bundle</a></li> <li><a href="https://github.com/Xceptance/neodymium-library">Neodymium</a></li> </ul> </li> <li>You can generate a new Selenide + Maven + JUnit5 sample project with just one line!</li> </ul> <p>For example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mvn archetype:generate -B -DarchetypeGroupId=org.selenide -DarchetypeArtifactId=selenide-junit5-archetype -DgroupId=com.example -DartifactId=ui-tests -Dpackage=com.example.project.ui </code></pre></div></div> <p>See <a href="https://github.com/vinogradoff/selenide-junit5-archetype">Maven Archetype Documentation</a> for further instructions.</p> <p><br /> I’ll be back!</p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2018/08/20/selenide-4.13.0/ https://selenide.org/2018/08/20/selenide-4.13.0 2018-08-20T00:00:00+00:00 Released Selenide 4.12.3 <p>Good day! The championship is finally finished, and we can get back to our favorite open-source projects.</p> <p>Today we released Selenide 4.12.3</p> <p>Let’s look what’s inside!</p> <p><br /></p> <h1 id="added-support-for-junit-5">Added support for JUnit 5</h1> <p>As you know, Selenide has special support for the most popular testing frameworks: JUnit4 and TestNG. It means special “@Rules” or “Listeners”, which can periodically restart a browser, make screenshots etc.</p> <p>Now we added similar support for JUnit 5 too:</p> <ul> <li><code class="language-plaintext highlighter-rouge">BrowserStrategyExtension</code></li> <li><code class="language-plaintext highlighter-rouge">ScreenShooterExtension</code></li> <li><code class="language-plaintext highlighter-rouge">SoftAssertsExtension</code></li> <li><code class="language-plaintext highlighter-rouge">TextReportExtension</code></li> </ul> <p>Thanks to <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/757">PR 757</a></p> <p>By the way, we have also rewritten <a href="https://github.com/selenide/selenide/tree/master/src/test/java">Selenide own tests</a> to JUnit5 and AssertJ. So you can look for JUnit5 examples there if you need.</p> <p><br /></p> <h1 id="timeout-for-downloading-files">Timeout for downloading files</h1> <p>As you know, Selenide has method <code class="language-plaintext highlighter-rouge">$.download()</code> for downloading files. It uses the standard setting <code class="language-plaintext highlighter-rouge">Configuration.timeout</code> to avoid too slow/hanging downloads.</p> <p>But some files are expected to download slowly. For example, when generating some heavy reports. For such cases we added a <code class="language-plaintext highlighter-rouge">download</code> method with <code class="language-plaintext highlighter-rouge">timeout</code> parameter:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">File</span> <span class="n">hugeReport</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#huge-report"</span><span class="o">).</span><span class="na">download</span><span class="o">(</span><span class="mi">100500</span><span class="o">);</span> </code></pre></div></div> <p>See <a href="https://github.com/selenide/selenide/issues/758">issue 758</a> - thanks to <a href="https://github.com/YuriIvanov">Yuri Ivanov</a> for <a href="https://github.com/selenide/selenide/pull/761">PR 761</a></p> <p><br /></p> <h1 id="collection-reloading-on-every-method-call">Collection reloading on every method call</h1> <p>This changes caused hot discussions.</p> <p>Collection is a list of matched elements returned by method<code class="language-plaintext highlighter-rouge">$$</code>. It returns ALL matched elements. Sometimes this list can be long. Sometimes it can make tests slower.</p> <h3 id="before">Before</h3> <p>Before version 4.10.1, Selenide always loaded the whole collection on every method call. That’s why a trivial <strong>iterating</strong> over big collection (few hundreds of elements) could be slow:</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">"span"</span><span class="o">).</span><span class="na">forEach</span><span class="o">(</span><span class="n">item</span> <span class="o">-&gt;</span> <span class="n">item</span><span class="o">.</span><span class="na">is</span><span class="o">(</span><span class="n">visible</span><span class="o">));</span> </code></pre></div></div> <h3 id="after">After</h3> <p>From Selenide 4.10.1, we started caching collections. The iterating became faster, but we got new complains. Some people store collection to a variable and do expect that it will be reloaded all the time:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">ElementsCollection</span> <span class="n">movieTitles</span> <span class="o">=</span> <span class="err">$$</span><span class="o">(</span><span class="s">".film"</span><span class="o">);</span> <span class="n">assertEquals</span><span class="o">(</span><span class="s">"Black Panther"</span><span class="o">,</span> <span class="n">movieTitles</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">getText</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">"sort"</span><span class="o">)).</span><span class="na">selectOption</span><span class="o">(</span><span class="s">"Release Date"</span><span class="o">);</span> <span class="n">assertEquals</span><span class="o">(</span><span class="s">"The Irishman"</span><span class="o">,</span> <span class="n">movieTitles</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">getText</span><span class="o">());</span> </code></pre></div></div> <p>In my opinion, this code is <em>unnatural</em>: if I expect the collection to be changed, it would be natural to call method <code class="language-plaintext highlighter-rouge">$$</code> once again. That’s why I didn’t want to revert caching for some time.</p> <p>But finally, “consistency” argument won. Method <code class="language-plaintext highlighter-rouge">$</code> does reload element on every method call, so <code class="language-plaintext highlighter-rouge">$$</code> should behave the same way.</p> <h3 id="now">Now</h3> <p>So we chose a compromise: <code class="language-plaintext highlighter-rouge">$$</code> reloads the collection on every method call <strong>except <code class="language-plaintext highlighter-rouge">$$.iterator()</code> and <code class="language-plaintext highlighter-rouge">$$.listIterator()</code></strong>. So the iteration will be fast, and elements will be reloaded (almost) always. I don’t know if it was the right decision. The new behavior can also cause some unexpected effects and pains. We will see.</p> <h3 id="snapshot">$$.snapshot()</h3> <p>By the way, if you want to cache the collection explicitly, we added method <code class="language-plaintext highlighter-rouge">$$.snapshot()</code>. It returns a current state of the collection - “snapshot”. It will not reload collection elements anymore. Iterating and any checks will be faster. You can you use this method when you know that the elements will not be loaded dynamically.</p> <p>See <a href="https://github.com/selenide/selenide/issues/696">issue 696</a></p> <h2 id="news">News</h2> <ul> <li>We found a <a href="https://www.slideshare.net/Provectus/selenide-review-and-how-to-start-using-it-in-legacy-selenium-tests">presentation about Selenide</a> by Alexander Bondarev from Determine from some Nerd’s Day at Provectus. There is also a <a href="https://www.youtube.com/watch?v=ekVSclpEdx0">video</a>.</li> <li>It finally happened! Selenide got to some <a href="https://image-store.slidesharecdn.com/3f9b2191-f339-4533-8ec4-dd7c6bc771b4-original.png">Technology Radar</a> with a title “Selenide as new standard”. See <a href="https://www.linkedin.com/feed/update/urn:li:activity:6424506901152829440/">source</a></li> <li>Welcome to <a href="https://aadays.pl/speakers/alexei-vinogradov/">Agile Automation Days</a> October 15-16 to see Workshop: Jump into the KISS UI-Test automation with Selenide</li> </ul> <p>Stay tuned!</p> <p><a href="https://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2018/07/17/selenide-4.12.3/ https://selenide.org/2018/07/17/selenide-4.12.3 2018-07-17T00:00:00+00:00 Released Selenide 4.12.2 <p>We released Selenide 4.12.2</p> <p>Let’s see what was changed there.</p> <p><br /></p> <h1 id="we-added-method-because-for-collections">We added method <code class="language-plaintext highlighter-rouge">because</code> for collections</h1> <p>As you know, Selenide has method <code class="language-plaintext highlighter-rouge">because</code> allowing test author to clarify why he expects this behaviour:</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">"#login"</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">because</span><span class="o">(</span><span class="s">"After 3 wrong answers user should be logged out"</span><span class="o">));</span> </code></pre></div></div> <p>Now we also have method <code class="language-plaintext highlighter-rouge">because</code> for 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="s">".error"</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><span class="na">because</span><span class="o">(</span><span class="s">"A separate error message per wrong answer"</span><span class="o">));</span> </code></pre></div></div> <p>See <a href="https://github.com/selenide/selenide/issues/440">issue 440</a> - thanks to <a href="https://github.com/sidelnikovmike">Mikhail Sidelnikov</a> for <a href="https://github.com/selenide/selenide/pull/749">PR 749</a></p> <p><br /></p> <h1 id="selenide-will-not-try-to-open-a-browser">Selenide will not try to open a browser</h1> <p>… if setting <code class="language-plaintext highlighter-rouge">Configuration.reopenBrowserOnFail</code> is <code class="language-plaintext highlighter-rouge">false</code>.</p> <p>Don’t be afraid, nothing will change for most of you. This setting is <code class="language-plaintext highlighter-rouge">true</code> by default.</p> <p>This setting was initially created for those who want to open/close browser entirely be themselves.</p> <p>See <a href="https://github.com/selenide/selenide/issues/695">issue 695</a> and <a href="https://github.com/selenide/selenide/pull/754">PR 754</a></p> <p><br /></p> <h1 id="we-upgraded-dependencies">We upgraded dependencies</h1> <ul> <li>selenium 3.13.0</li> <li>webdrivermanager 2.2.3</li> </ul> <p><br /></p> <p><br /></p> <p><a href="https://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2018/06/27/selenide-4.12.2/ https://selenide.org/2018/06/27/selenide-4.12.2 2018-06-27T00:00:00+00:00 Released Selenide 4.12.1 <p>Good summer!</p> <p>With some delay, we post the Selenide 4.12.1 release notes.</p> <p><br /></p> <h1 id="fixed-name-of-downloaded-file">Fixed name of downloaded file</h1> <p>When you download a file with link containing <code class="language-plaintext highlighter-rouge">?</code> and parameters (like <code class="language-plaintext highlighter-rouge">/download/me/selenide-4.11.5.md?sessioncookie=12345</code>), Selenide created a local file with name <code class="language-plaintext highlighter-rouge">selenide-4.11.5.md?sessioncookie=12345</code>.</p> <p>Now Selenide will cut all characters from <code class="language-plaintext highlighter-rouge">?</code>. In this case, it will create a file <code class="language-plaintext highlighter-rouge">selenide-4.11.5.md</code>.</p> <p>See <a href="https://github.com/selenide/selenide/issues/735">issue 735</a> - thanks to <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/735">PR 735</a></p> <p><br /></p> <h1 id="changed-implementation-of-method-seleniderefresh">Changed implementation of method <code class="language-plaintext highlighter-rouge">Selenide.refresh()</code></h1> <p>This method sometimes didn’t actually refresh the page.<br /> We could not reproduce it, but blindly changed the implementation - now it just calls built-in selenium method<br /> <code class="language-plaintext highlighter-rouge">webdriver.navigate().refresh()</code>. Seems that it fixed the problem.</p> <p>See <a href="https://github.com/selenide/selenide/issues/740">issue 740</a> - thanks to <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/741">PR 741</a></p> <p><br /></p> <h1 id="fixed-method-webdriverrunnerisheadless">Fixed method <code class="language-plaintext highlighter-rouge">WebDriverRunner.isHeadless()</code></h1> <p>This method returned <code class="language-plaintext highlighter-rouge">true</code> only for HtmlUnit and PhantomJS. Now it returns <code class="language-plaintext highlighter-rouge">true</code> also for Chrome/Firefox when executed in <code class="language-plaintext highlighter-rouge">headless</code> mode.</p> <p>(Though I personally don’t understand why one needs to use this method. Don’t use it. Do you really need Selenide help to know what browser you have started?)</p> <p>See <a href="https://github.com/selenide/selenide/issues/750">issue 750</a> - thanks to <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/751">PR 751</a></p> <p><br /></p> <h1 id="added-thread-id-to-log-messages-on-closewebdriver-method">Added thread ID to log messages on closeWebDriver() method</h1> <p>For some people, it was sometimes hard to understand which thread closed the driver. Now it will be easier.</p> <p>(Though I personally don’t understand why it should be a problem)</p> <p>See <a href="https://github.com/selenide/selenide/issues/582">issue 582</a> - thanks to <a href="https://github.com/AlexanderPoleschuk">Alexander Poleschuk</a> for <a href="https://github.com/selenide/selenide/pull/737">PR 737</a></p> <p><br /></p> <h1 id="declared-webdrivermanager-dependency-as-api">Declared <code class="language-plaintext highlighter-rouge">webdrivermanager</code> dependency as <code class="language-plaintext highlighter-rouge">api</code></h1> <p>Now you can use webdrivermanager from your code without declaring any additional dependencies.</p> <p>Thanks to <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/736">PR 736</a></p> <p><br /></p> <h1 id="migrated-from-coveralls-to-sonarcloud">Migrated from <code class="language-plaintext highlighter-rouge">coveralls</code> to <code class="language-plaintext highlighter-rouge">sonarcloud</code></h1> <p>for measuring Selenide own test coverage. It doesn’t affect you directly, just FYI.</p> <p>See <a href="https://github.com/selenide/selenide/issues/702">issue 702</a> - thanks to <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/744">PR 744</a></p> <p><br /></p> <p><br /></p> <p><a href="https://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2018/06/02/selenide-4.12.1/ https://selenide.org/2018/06/02/selenide-4.12.1 2018-06-02T00:00:00+00:00 Released Selenide 4.11.4 <p>We made a mini release Selenide 4.11.4</p> <p><br /></p> <h1 id="removed-spam-in-logs-from-firefox-driver">Removed spam in logs from Firefox driver</h1> <p>See <a href="https://github.com/selenide/selenide/issues/673">issue 673</a> - thanks to <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/732">PR 732</a></p> <p><br /></p> <h1 id="upgraded-dependencies">Upgraded dependencies</h1> <ul> <li>selenium 3.12.0</li> <li>gson:2.8.4</li> <li>guava:25.0</li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2018/05/09/selenide-4.11.4/ https://selenide.org/2018/05/09/selenide-4.11.4 2018-05-09T00:00:00+00:00 Released Selenide 4.11.3 <p>We released Selenide 4.11.3. Let’s see what updates it contains:</p> <p><br /></p> <h1 id="reveal-selenide-proxy-server">You can now get access to proxy server</h1> <p>As you know, Selenide starts a built-in proxy server (BrowserMobProxy). But until now, you could not use it because it was private. Selenide used it only for downloading files.</p> <p>Now we added a public method which allows you to get the <code class="language-plaintext highlighter-rouge">BrowserMobProxy</code> instance and use as you wish:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">BrowserMobProxy</span> <span class="n">bmp</span> <span class="o">=</span> <span class="nc">WebDriverRunner</span><span class="o">.</span><span class="na">getSelenideProxy</span><span class="o">().</span><span class="na">getProxy</span><span class="o">();</span> </code></pre></div></div> <p>Please tell us in comments how you are going to use it!</p> <p>P.S. Selenide still starts proxy server only when <code class="language-plaintext highlighter-rouge">Configuration.fileDownload=PROXY</code>. Probably we will break this dependency in next version.</p> <p>Thanks to <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/731">PR 731</a></p> <p><br /></p> <h1 id="add-css-value-check">We added condition <code class="language-plaintext highlighter-rouge">cssValue</code></h1> <p>Now you can check CSS properties 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">"input"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">cssValue</span><span class="o">(</span><span class="s">"font-size"</span><span class="o">,</span> <span class="s">"12"</span><span class="o">));</span> </code></pre></div></div> <p>See <a href="https://github.com/selenide/selenide/issues/628">issue 628</a> - thanks to <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/727">PR 727</a></p> <p>Attention! Use this check with caution. Such checks can make your tests too fragile. You don’t want to have tests that fail often just because of minor design tunings, right?</p> <p>And remember that Selenium method <code class="language-plaintext highlighter-rouge">getCssValue</code> can return different results for different browsers. For example, you cannot just write a universal check for all browsers: <code class="language-plaintext highlighter-rouge">$("input").shouldHave(cssValue("color", "#000000"))</code>, because</p> <ul> <li>For Chrome, it is <code class="language-plaintext highlighter-rouge">rgb(0, 0, 0)</code></li> <li>For Firefox, it is <code class="language-plaintext highlighter-rouge">rgba(0, 0, 0, 0)</code></li> </ul> <p><br /></p> <h1 id="remove-wrong-logback-dependency">We removed wrong dependency <code class="language-plaintext highlighter-rouge">logback-classic</code></h1> <p>As you probably remember, in previous Selenide version there was introduces an extra dependency WebDriverManager -&gt; logback, and we recommended to exclude it in your build script.</p> <p>Now you can remove these lines:</p> <div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">exclude</span> <span class="nl">group:</span> <span class="s2">"ch.qos.logback"</span><span class="o">,</span> <span class="nl">module:</span> <span class="s2">"logback-classic"</span> </code></pre></div></div> <p><br /></p> <h1 id="remove-duplicate-screenshots">Removed duplicate screenshots</h1> <p>Starting from version 4.11.0 Selenide created duplicate screenshots in some cases. Now we fixed it.</p> <p>See <a href="https://github.com/selenide/selenide/issues/729">issue 729</a> - thanks to <a href="https://github.com/BorisOsipov">Boris Osipov</a> for <a href="https://github.com/selenide/selenide/pull/730">PR 730</a></p> <p><br /></p> <h1 id="support-browser-binary-for-remote-browser">Implemented using of <code class="language-plaintext highlighter-rouge">browserBinary</code> setting in case of remote browser</h1> <p>Starting from version 4.9, Selenide has a setting for <a href="/2017/12/20/selenide-4.9/">browser binary path</a> - <code class="language-plaintext highlighter-rouge">Configuration.browserBinary</code>. But it was used only for local browser.</p> <p>Now Selenide also uses this setting for remote browser.</p> <p>See <a href="https://github.com/selenide/selenide/issues/725">issue 725</a> - thanks to <a href="https://github.com/vinogradoff">Alexei Vinogradov</a> for <a href="https://github.com/selenide/selenide/pull/726">PR 726</a></p> <p><br /></p> <h2 id="news">News</h2> <ul> <li>Another <a href="https://www.youtube.com/watch?v=sHPaj1kTgGY&amp;feature=youtu.be">video tutorial</a> about Selenide</li> <li>See you in Kraków, May, 9-11 at <a href="https://2018.geecon.org/speakers/">GeeCon conference</a> - I will present Selenide there.</li> </ul> <p>Stay tuned!</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2018/05/08/selenide-4.11.3/ https://selenide.org/2018/05/08/selenide-4.11.3 2018-05-08T00:00:00+00:00 Released Selenide 4.11.2 <p>Dear friends, we released Selenide 4.11.2. Below you can find the notable changes of this release.</p> <p><br /></p> <h1 id="now-you-can-make-screenshots-inside-iframe">Now you can make screenshots inside <code class="language-plaintext highlighter-rouge">iframe</code></h1> <p>You can find examples in <a href="https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/ScreenshotInIframeTest.java">ScreenshotInIframeTest</a>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">SelenideElement</span> <span class="n">iframe</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#iframe_page"</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">"#small_div"</span><span class="o">);</span> <span class="nc">File</span> <span class="n">file</span> <span class="o">=</span> <span class="nc">Screenshots</span><span class="o">.</span><span class="na">takeScreenShot</span><span class="o">(</span><span class="n">iframe</span><span class="o">,</span> <span class="n">element</span><span class="o">);</span> </code></pre></div></div> <p>Thanks to <a href="https://github.com/andrejska">Andrejs Kalnačs</a> for <a href="https://github.com/selenide/selenide/pull/705">PR 705</a></p> <p><br /></p> <h1 id="we-added-method-atbottom">We added method <code class="language-plaintext highlighter-rouge">atBottom()</code></h1> <p>Now you can check if a page is scrolled to the bottom:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">assertFalse</span><span class="o">(</span><span class="n">atBottom</span><span class="o">());</span> <span class="n">executeJavaScript</span><span class="o">(</span><span class="s">"return window.scrollTo(0, document.body.scrollHeight);"</span><span class="o">);</span> <span class="n">assertTrue</span><span class="o">(</span><span class="n">atBottom</span><span class="o">());</span> </code></pre></div></div> <p>You can find examples in <a href="https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/PageAtBottomTest.java">PageAtBottomTest</a></p> <p>Thanks to <a href="https://github.com/pavelpp">pavelpp</a> for <a href="https://github.com/selenide/selenide/pull/646">PR 646</a></p> <p><br /></p> <h1 id="we-added-setting-setvaluechangeevent">We added setting <code class="language-plaintext highlighter-rouge">setValueChangeEvent</code></h1> <p>As you probably know, methods <code class="language-plaintext highlighter-rouge">$.append()</code> and <code class="language-plaintext highlighter-rouge">$.setValue()</code> trigger few events after setting a value to the input field, including the <code class="language-plaintext highlighter-rouge">change</code> event. We recently realized that it’s wrong, because the <code class="language-plaintext highlighter-rouge">change</code> even should be triggered by browser.</p> <p>It also caused problems in some cases - for example, when this <code class="language-plaintext highlighter-rouge">change</code> event caused focus moving to the next element in DOM which was actually outside of viewport.</p> <p>Don’t panic, Selenide behaviour hasn’t changed by default. Default value is <code class="language-plaintext highlighter-rouge">setValueChangeEvent=true</code>.</p> <p>If you agree with our reasoning, disable triggering <code class="language-plaintext highlighter-rouge">change</code> event via system property:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-Dselenide.setValueChangeEvent=false </code></pre></div></div> <p>or right in 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">setValueChangeEvent</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span> </code></pre></div></div> <p>If you disagree, feel free to share your thoughts. Let’s discuss it!</p> <p>Thanks to <a href="https://github.com/MikeShysh">MikeShysh</a> for <a href="https://github.com/selenide/selenide/pull/718">PR 718</a></p> <p><br /></p> <h1 id="we-upgraded-dependencies">We upgraded dependencies</h1> <ul> <li>htmlunit:2.30</li> <li>webdrivermanager:2.2.1</li> </ul> <p>If you use a custom <code class="language-plaintext highlighter-rouge">SLF4J</code> implementation, you may get some spam in logs like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/Users/arasolka/.gradle/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-slf4j-impl/2.11.0/9ba207b78e470fe7765ebee14f1f0336c9cbcc18/log4j-slf4j-impl-2.11.0.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: Found binding in [jar:file:/Users/arasolka/.gradle/caches/modules-2/files-2.1/ch.qos.logback/logback-classic/1.2.3/7c4f3c474fb2c041d8028740440937705ebb473a/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation. SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory] </code></pre></div></div> <p>To remove this spam, ignore the transitive dependency of <code class="language-plaintext highlighter-rouge">webdrivermanager</code>:</p> <div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">configurations</span><span class="o">.</span><span class="na">all</span> <span class="o">{</span> <span class="n">exclude</span> <span class="nl">group:</span> <span class="s2">"ch.qos.logback"</span><span class="o">,</span> <span class="nl">module:</span> <span class="s2">"logback-classic"</span> <span class="o">}</span> </code></pre></div></div> <p>We will fix it in next Selenide version.</p> <h2 id="statistics">Statistics</h2> <p>We haven’t posted Selenide download statistics for a long time. And it is growing! A year ago there were 8000, now 18000 downloads in a month.</p> <center> <img src="/images/2018/04/selenide.downloads.png" width="800" /> </center> <p>Life is going on!</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2018/04/25/selenide-4.11.2/ https://selenide.org/2018/04/25/selenide-4.11.2 2018-04-25T00:00:00+00:00 Released Selenide 4.11.1 <p>Dear friends, We recently moved to “Semantic versioning”. Now Selenide versions will be called 4.11.x and released more often.</p> <p>In Selenide 4.11.1 we did only one fix:</p> <p><br /></p> <h1 id="fixed-a-problem-with-hanging-chrome-on-windows">Fixed a problem with hanging Chrome on Windows</h1> <p>Windows users complained that even after calling <code class="language-plaintext highlighter-rouge">Selenide.close()</code> process <code class="language-plaintext highlighter-rouge">chrome.exe</code> still hangs in task manager. Though it’s not a Selenide bug, we managed to tune webdriver settings, so that Chrome is properly closed now.</p> <p>Thanks to <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/711">PR 711</a>!</p> <p><br /></p> <p>That’s it. Selenide 4.11.2 is coming soon!</p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2018/04/03/selenide-4.11.1/ https://selenide.org/2018/04/03/selenide-4.11.1 2018-04-03T00:00:00+00:00 Released Selenide 4.11.0 <p>Good morning, my friends!</p> <p>We released Selenide 4.11.0. What’s new there?</p> <p><br /></p> <h1 id="upgraded-to-selenium-3110">Upgraded to selenium 3.11.0</h1> <p>The main <a href="https://raw.githubusercontent.com/SeleniumHQ/selenium/master/java/CHANGELOG">changes in selenium 3.11.0</a> are about Internet Explorer and Windows platform.</p> <p>And also:</p> <ul> <li>removed methods <code class="language-plaintext highlighter-rouge">startClient</code> and <code class="language-plaintext highlighter-rouge">stopClient</code> in class <code class="language-plaintext highlighter-rouge">RemoteWebDriver</code></li> <li>remove properties <code class="language-plaintext highlighter-rouge">SafariOptions.cleanSession</code> and <code class="language-plaintext highlighter-rouge">SafariOptions.port</code></li> </ul> <p><br /></p> <h1 id="added-collection-condition-textsinanyorder">Added collection condition <code class="language-plaintext highlighter-rouge">textsInAnyOrder</code></h1> <p>Now you can write more advanced check for 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="na">shouldHave</span><span class="o">(</span><span class="n">textsInAnyOrder</span><span class="o">(</span><span class="s">"Push"</span><span class="o">,</span> <span class="s">"Image"</span><span class="o">,</span> <span class="s">"Email"</span><span class="o">))</span> </code></pre></div></div> <p>See <a href="https://github.com/selenide/selenide/issues/478">issue 478</a> – thanks to <a href="https://github.com/hyunil-shin">hyunil-shin</a> for <a href="https://github.com/selenide/selenide/pull/589">PR 589</a></p> <p><br /></p> <h1 id="now-you-can-set-browser-position">Now you can set browser position</h1> <p>As usually, either via system property:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">-Dselenide</span>.browserPosition<span class="o">=</span>300x200 </code></pre></div></div> <p>or in 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">browserPosition</span> <span class="o">=</span> <span class="s">"400x300"</span><span class="o">;</span> </code></pre></div></div> <p>See <a href="https://github.com/selenide/selenide/issues/687">issue 687</a> – thanks to <a href="https://github.com/rosolko">Aliaksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/687">PR 687</a></p> <p><br /></p> <h1 id="now-selenide-can-download-files-with-non-ascii-characters-in-name">Now Selenide can download files with non-ascii characters in name</h1> <p>Now this code will work correctly:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">File</span> <span class="n">file</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"a"</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">"файл-с-русским-названием.txt"</span><span class="o">);</span> </code></pre></div></div> <p>Before this release, Selenide created a file with name <code class="language-plaintext highlighter-rouge">-------.txt</code></p> <p>See <a href="https://github.com/selenide/selenide/issues/688">issue 688</a> and <a href="https://github.com/selenide/selenide/pull/689">PR 689</a></p> <p><br /></p> <h1 id="now-you-can-pass-chromeoptionsprefs-to-webdriver">Now you can pass <code class="language-plaintext highlighter-rouge">chromeoptions.prefs</code> to webdriver</h1> <p>Similar to <code class="language-plaintext highlighter-rouge">chromeoptions.args</code>, now you can pass parameter <code class="language-plaintext highlighter-rouge">chromeoptions.prefs</code> to your tests:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">-Dchromeoptions</span>.prefs<span class="o">=</span>profile.block_third_party_cookies<span class="o">=</span><span class="nb">false</span>,profile.avatar_index<span class="o">=</span>26 </code></pre></div></div> <p>See <a href="https://github.com/selenide/selenide/pull/692">PR 692</a> - thanks to <a href="https://github.com/sirdir">Tymur Kubai</a></p> <p><br /></p> <h1 id="now-you-can-add-your-own-interceptor-to-selenide-built-in-proxy-server">Now you can add your own interceptor to Selenide built-in proxy server</h1> <p>People asked for this feature for a long time. And we finally did it!</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">addRequestFilter</span><span class="o">(</span><span class="s">"proxy-usages.request"</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="n">getSelenideProxy</span><span class="o">().</span><span class="na">addResponseFilter</span><span class="o">(</span><span class="s">"proxy-usages.response"</span><span class="o">,</span> <span class="k">new</span> <span class="nc">ResponseFilter</span><span class="o">()</span> <span class="o">{...});</span> </code></pre></div></div> <p>In <code class="language-plaintext highlighter-rouge">RequestFilter</code> and <code class="language-plaintext highlighter-rouge">ResponseFilter</code> subclasses you can do pretty anything that is not possible in pure Selenium: log requests/responses between browser and server, measure times, get http status, modify request or response body, inject custom JavaScript to html etc. This is the <em>god mode</em> in Selenide!</p> <p>I hope you are going to use the god mode to make your tests more fast and stable.</p> <p>As usually, you can find sample usages <a href="https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/proxy/ProxyServerUsageTest.java">in Selenide own tests</a>.</p> <p>NB! Now Selenide starts its built-in proxy server only if <code class="language-plaintext highlighter-rouge">Configuration.fileDownload=PROXY</code>.</p> <p>Probably we should break this dependency. Feel free to send your feedback.</p> <p><br /></p> <h1 id="method-followlink-was-marked-as-deprecated">Method <code class="language-plaintext highlighter-rouge">$.followLink()</code> was marked as deprecated</h1> <p>Nobody remembers why it was created 7 years ago. But now you can just use <code class="language-plaintext highlighter-rouge">$.click()</code> instead.</p> <p><br /></p> <h1 id="fixed-a-occasional-nullpointerexception-in-selenidereport">Fixed a occasional NullPointerException in SelenideReport</h1> <p>Nobody knows how to reproduce it, but we had to fix it.</p> <p>Thanks to <a href="https://github.com/dkorobtsov">dkorobtsov</a> for <a href="https://github.com/selenide/selenide/pull/686">PR 686</a></p> <p><br /></p> <h1 id="we-fixed-a-problem-when-selenide-didnt-take-screenshot-in-soft-asserts">We fixed a problem when Selenide didn’t take screenshot in soft asserts</h1> <p>See <a href="https://github.com/selenide/selenide/issues/655">issue 655</a> - thanks to <a href="https://github.com/BorisOsipov">Boris Osipov</a> for <a href="https://github.com/selenide/selenide/pull/659">PR 659</a></p> <p><br /></p> <h2 id="news">News</h2> <ul> <li>Wow! <a href="https://docs.qameta.io/allure/#_selenide">Allure implemented Selenide support</a></li> <li>Selenide started using “semantic versioning”. Next Selenide versions will be 4.11.1, 4.11.2, 4.11.3 etc.</li> <li>Selenide got two new committers. <ul> <li><a href="https://github.com/BorisOsipov">Boris Osipov</a></li> <li><a href="https://github.com/rosolko">Aliaksandr Rasolka</a></li> </ul> <p>We are growing!</p> </li> </ul> <h2 id="resources">Resources</h2> <ul> <li><a href="https://docviewer.yandex.ee/view/0/?*=8tBKEPLAMQW8t2PRjyqwqnpdneR7InVybCI6InlhLWRpc2stcHVibGljOi8vcFN3SHRMY1QwQi96UCtYNXhSOXI4TTBGNzhxOEo4amFWWW5uNHA2YmNNYz0iLCJ0aXRsZSI6IkFsbHVyZSBpbnRlZ3JhdGlvbnMucGRmIiwidWlkIjoiMCIsInl1IjoiOTExNzE4NDM2MTUxODEyMzY5MCIsIm5vaWZyYW1lIjpmYWxzZSwidHMiOjE1MTgxMjM3NTkwOTF9">Integration with Allure</a> (including Selenide, of course)</li> <li>Tutorial for beginners: <a href="https://installselenium.weebly.com/">An installer for Selenide</a></li> <li>Selenide was mentioned in book <a href="https://books.google.ee/books?id=nszcDgAAQBAJ&amp;pg=PA258&amp;lpg=PA258&amp;dq=%22selenide%22+java&amp;source=bl&amp;ots=9nGbDkOllN&amp;sig=_Q1Qvlxv7c0W1w7FO7_7yQK0WFc&amp;hl=en&amp;sa=X&amp;ved=0ahUKEwir-IHg0tjZAhUGtRQKHbD3CFM4MhDoAQgzMAI#v=onepage&amp;q=%22selenide%22%20java&amp;f=false">Learning Vue.js 2</a></li> <li>A talk <a href="http://aadays.pl/wp-content/uploads/2017/10/Presentation_Selenide_AADays.pdf">about Selenide on AADays</a> in Poland</li> </ul> <p><br /> And a whole bunch of materials about in Japanese:</p> <ul> <li><a href="http://backpaper0.github.io/ghosts/try-selenide/">70 pages tutorial</a></li> <li>One more <a href="https://qiita.com/tashxii/items/78e9288f7956a81caac1">hello world with Selenide and a servlet</a></li> <li>A post about <a href="https://qiita.com/tenten0213/items/24ab7872ce26bbc47f18">a problem with <code class="language-plaintext highlighter-rouge">sendKeys</code> in headless Chrome and its solutions with Selenide</a></li> <li>http://www.atmarkit.co.jp/ait/articles/1803/05/news010.html</li> <li>https://qiita.com/shimashima35/items/918b26c4260e764ce90a</li> </ul> <p><br /> See you soon! <br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2018/04/02/selenide-4.11/ https://selenide.org/2018/04/02/selenide-4.11 2018-04-02T00:00:00+00:00 Released Selenide 4.10 <p>Good night, Seleniders!</p> <p>We recently got a chance to merge a lot of pull requests and released Selenide 4.10</p> <p>So, what’s new there?</p> <p><strong>What you get when update to Selenide 4.10</strong>?</p> <p><br /></p> <h1 id="we-added-method-scrollintoview">We added method <code class="language-plaintext highlighter-rouge">$.scrollIntoView()</code></h1> <p>You can use it to scroll browser to the right place. For example, it can be useful to overcome issues of some browser which cannot click an element that is outside of visible window area.</p> <p>So, method <code class="language-plaintext highlighter-rouge">$.scrollIntoView()</code> says browser to scroll the page so that the element was in a visible area.</p> <p>Method can have either boolean 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">"#my-button"</span><span class="o">).</span><span class="na">scrollIntoView</span><span class="o">(</span><span class="kc">true</span><span class="o">);</span> <span class="c1">// the top of the element will be aligned to the top</span> <span class="err">$</span><span class="o">(</span><span class="s">"#my-button"</span><span class="o">).</span><span class="na">scrollIntoView</span><span class="o">(</span><span class="kc">false</span><span class="o">);</span> <span class="c1">// the bottom of the element will be aligned to the bottom</span> </code></pre></div></div> <p>or more advanced String 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">"#my-button"</span><span class="o">).</span><span class="na">scrollIntoView</span><span class="o">(</span><span class="s">"{block: \"end\"}"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#my-button"</span><span class="o">).</span><span class="na">scrollIntoView</span><span class="o">(</span><span class="s">"{behavior: \"instant\", block: \"end\", inline: \"nearest\"}"</span><span class="o">);</span> </code></pre></div></div> <p>Read javadoc for the details.</p> <p>See <a href="https://github.com/selenide/selenide/issues/649">issue 649</a></p> <p>Thanks to <a href="https://github.com/rosolko">Aleksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/656">pull request 656</a>.</p> <p><br /></p> <h1 id="now-tou-can-run-headless-browsers-on-selenium-grid">Now tou can run <em>headless</em> browsers on Selenium Grid</h1> <p>If you run tests on Selenium Grid, you can now open browsers in <em>headless</em> mode. You need only couple of lines to achieve that:</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">"http://selenium-grid-host:port/wd/hub"</span><span class="o">;</span> <span class="nc">Configuration</span><span class="o">.</span><span class="na">headless</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span> </code></pre></div></div> <p>See <a href="https://github.com/selenide/selenide/issues/660">issue 660</a></p> <p>Thanks to <a href="https://github.com/BorisOsipov">Boris Osipov</a> for <a href="https://github.com/selenide/selenide/pull/661">pull request 661</a>.</p> <p><br /></p> <h1 id="now-you-can-set-custom-capabilities-for-chrome-and-firefox">Now you can set custom capabilities for Chrome and Firefox</h1> <p>You can set custom capabilities in <code class="language-plaintext highlighter-rouge">Configuration</code>, and Selenide will use them when opening a browser:</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">browserCapabilities</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">DesiredCapabilities</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">SOME_CAP</span><span class="o">,</span> <span class="s">"SOME_VALUE_FROM_CONFIGURATION"</span><span class="o">);</span> </code></pre></div></div> <p>See <a href="https://github.com/selenide/selenide/issues/556">issue 556</a></p> <p>Thanks to <a href="https://github.com/SergeyPirogov">Sergey Pirogov</a> for <a href="https://github.com/selenide/selenide/pull/556">pull request 556</a> and <a href="https://github.com/BorisOsipov">Boris Osipov</a> for <a href="https://github.com/selenide/selenide/pull/664">pull request 664</a>.</p> <p><br /></p> <h1 id="we-optimized-performance-of--iteration">We optimized performance of <code class="language-plaintext highlighter-rouge">$$</code> iteration</h1> <p>Some of Seleniders found that such collection iteration can be slow:</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">"span"</span><span class="o">).</span><span class="na">forEach</span><span class="o">(</span><span class="n">item</span> <span class="o">-&gt;</span> <span class="n">item</span><span class="o">.</span><span class="na">is</span><span class="o">(</span><span class="n">visible</span><span class="o">));</span> </code></pre></div></div> <p>Because Selenide reloads all collection elements on every step. See <a href="https://github.com/selenide/selenide/issues/641">issue 641</a></p> <p>We fixed that. Now the loop should be much faster. Thanks to <a href="https://github.com/CaBocuk">Artem Savosik</a> for <a href="https://github.com/selenide/selenide/pull/653">pull request 653</a>.</p> <p><br /></p> <h1 id="we-added-user-agent-header-when-downloading-a-file">We added “User-Agent” header when downloading a file</h1> <p>As you probably know, Selenide downloads files by issuing a separate http request, copying all cookies from browser to it. Sometimes it’s not enough, because application also checks <code class="language-plaintext highlighter-rouge">User-Agent</code> in addition to session cookie. And method <code class="language-plaintext highlighter-rouge">$().download()</code> didn’t work in this case.</p> <p>See <a href="https://github.com/selenide/selenide/issues/639">issue 639</a></p> <p>Now Selenide also copies <code class="language-plaintext highlighter-rouge">User-Agent</code> header from browser to http request for downloading file. Method <code class="language-plaintext highlighter-rouge">$().download()</code> should work.</p> <p>Thanks to <a href="https://github.com/rosolko">Aleksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/657">pull request 657</a>.</p> <p><br /></p> <h1 id="now-methods-bytext-and-withtext-understand-unbreakable-spaces">Now methods <code class="language-plaintext highlighter-rouge">byText</code> and <code class="language-plaintext highlighter-rouge">withText</code> understand unbreakable spaces</h1> <p>Imagine that you have such an element on a page:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;span&gt;</span>Hello<span class="ni">&amp;nbsp;</span>world<span class="nt">&lt;/span&gt;</span> </code></pre></div></div> <p>By now, command <code class="language-plaintext highlighter-rouge">$(byText("Hello world"))</code> or <code class="language-plaintext highlighter-rouge">$(withText("Hello world"))</code> could not find it. Now it can.</p> <p>We improved methods <code class="language-plaintext highlighter-rouge">byText</code> and <code class="language-plaintext highlighter-rouge">withText</code> to understand non-breakable spaces, or characters <code class="language-plaintext highlighter-rouge">&amp;nbsp</code> or <code class="language-plaintext highlighter-rouge">\u00A0</code>. Now these characters are treated as usual spaces.</p> <p>See <a href="https://github.com/selenide/selenide/issues/597">issue 597</a></p> <p><br /></p> <h1 id="upgraded-to-phantomjsdriver-144">Upgraded to phantomjsdriver 1.4.4</h1> <p>Which in turn was upgraded to selenium-java 3.8.1 (and doesn’t have any other changes).</p> <p><br /></p> <h1 id="upgraded-to-htmlunit-229-and-guava236-jre">Upgraded to htmlunit 2.29 and guava:23.6-jre</h1> <p>… just in case</p> <p><br /></p> <h2 id="news">News</h2> <p>I warmly welcome you to the great <a href="https://seleniumcamp.com/">SeleniumCamp</a> conference!</p> <p>2 days, 3 tracks, 500+ attendees. And Kiev is a beautiful city.</p> <p>See you on SeleniumCamp 2-3 2-3.03.2018</p> <p><br /> Happy New @Deprecated Year! <br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2018/01/12/selenide-4.10/ https://selenide.org/2018/01/12/selenide-4.10 2018-01-12T00:00:00+00:00 Released Selenide 4.9 <p>Good night!</p> <p>At the very last moment of year 2017, we released Selenide 4.9.</p> <p>What’s new there?</p> <h1 id="upgraded-to-selenium-381">Upgraded to selenium 3.8.1</h1> <p>There are <a href="https://raw.githubusercontent.com/SeleniumHQ/selenium/master/java/CHANGELOG">backward-incompatible changes</a>, be prepared. Selenium guys like to delete existing functionality :)</p> <p>Thanks to <a href="https://github.com/rosolko">Aleksandr Rasolka</a> for <a href="https://github.com/selenide/selenide/pull/638">pull request 638</a>.</p> <p><br /></p> <h1 id="now-marionette-is-used-by-default">Now marionette is used by default</h1> <p>As you know, Selenide initially used Firefox as a default browser. The reason is simple: it was the only webdriver that didn’t require downloading a separate binary to drive the browser.</p> <p>Later the situation changed. FireFoxDriver doesn’t support newer Firefox version anymore, it was replaced by GeckoDriver (aka Marionette). It requires downloading of a separate binary file, but now Selenide can download it automatically.</p> <p>So, when you don’t set browser, Selenide now uses Marionette by default (which means Firefox). Though, I personally prefer Chrome.</p> <p>Thanks to <a href="https://github.com/ostap-oleksyn">Ostap Oleksyn</a> for <a href="https://github.com/selenide/selenide/pull/621">pull request 621</a>.</p> <p><br /></p> <h1 id="fixed-initialization-of-elements-inside-elementscontainer-but-without-findby-annotation">Fixed initialization of elements inside ElementsContainer but without @FindBy annotation</h1> <p>See <a href="https://github.com/selenide/selenide/issues/617">issue 617</a></p> <p>Thanks to <a href="https://github.com/CaBocuk">Artem Savosik</a> for <a href="https://github.com/selenide/selenide/pull/618">pull request 618</a>.</p> <p>Though, I personally don’t use <code class="language-plaintext highlighter-rouge">ElementsContainer</code> and recommend you not to use. Selenide allows writing page objects / page containers much easier.</p> <p><br /></p> <h1 id="added-methods-itemfirst3-and-itemlast3">Added methods <code class="language-plaintext highlighter-rouge">$$(“.item”).first(3)</code> and <code class="language-plaintext highlighter-rouge">$$(“.item”).last(3)</code></h1> <p>These methods allow to get few elements from the beginning or end of list. It can be useful when the list is too long, or its length is unknown, and you need to verify only some of elements.</p> <p>See. <a href="https://github.com/selenide/selenide/issues/623">issue 623</a></p> <p>Thanks to <a href="https://github.com/ostap-oleksyn">Ostap Oleksyn</a> for <a href="https://github.com/selenide/selenide/pull/624">pull request 624</a>.</p> <p><br /></p> <h1 id="add-ability-to-set-browser-binary-path-using-configuration-parameter">Add ability to set browser binary path using configuration parameter</h1> <p>Sometimes people want to run tests with different versions of the same browser. With stable chrome, Canary, nightly build…</p> <p>Now you can set explicitly the path to browser binary. Either using system property:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-Dselenide.browserBinary=/usr/lib/chrome.exe </code></pre></div></div> <p>or right in the 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">browserBinary</span> <span class="o">=</span> <span class="s">"/usr/lib/firefox"</span><span class="o">;</span> </code></pre></div></div> <p>Thanks to <a href="https://github.com/ostap-oleksyn">Ostap Oleksyn</a> for <a href="https://github.com/selenide/selenide/pull/627">pull request 627</a>.</p> <p><br /></p> <h1 id="fixed-method-prompt-in-htmlunit">Fixed method <code class="language-plaintext highlighter-rouge">prompt()</code> in HtmlUnit</h1> <p>Thanks to <a href="https://github.com/simple-elf">Anton Aftakhov</a> for <a href="https://github.com/selenide/selenide/pull/634">pull request 634</a></p> <p><br /></p> <h1 id="upgraded-dependencies">Upgraded dependencies</h1> <ul> <li>webdrivermanager:2.0.1</li> <li>guava:23.5-jre</li> <li>httpcore:4.4.8</li> <li>htmlunit-driver:2.28.2</li> </ul> <h2 id="news">News</h2> <ul> <li>How to run Selenide tests on Amazon Lambda <a href="https://aws.amazon.com/blogs/devops/ui-testing-at-scale-with-aws-lambda/">UI Testing at Scale with AWS Lambda</a></li> <li>My article in Java Advent Calendar: <a href="https://www.javaadvent.com/2017/12/flaky-tests.html">Flaky tests</a></li> <li>Article in Japanese: <a href="https://qiita.com/shimashima35/items/411f99a27b7ec5503532">Using WebDriverManager with Selenide</a></li> <li>One more: <a href="https://qiita.com/motoki1990/items/abe3b7472097d7e6085f">Toward people who want to utilize Selenide</a></li> <li>https://www.linkedin.com/pulse/awesome-reporting-vigo-selenide-kushan-shalindra-amarasiri-</li> <li>An article from japanese “Selenium/Appium Advent Calendar 2017”: <a href="https://qiita.com/shimashima35/items/0575ac5488edd6942d5a">How to record video with Selenide and Monte recorder</a></li> <li>An article about <a href="https://www.linkedin.com/pulse/awesome-reporting-vigo-selenide-kushan-shalindra-amarasiri-">test reports with Selenide and Vigo Reporting</a></li> </ul> <p><br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2017/12/20/selenide-4.9/ https://selenide.org/2017/12/20/selenide-4.9 2017-12-20T00:00:00+00:00 Released Selenide 4.8 <p>Good evening!</p> <p>We released Selenide 4.8. It’s mainly a Selenium upgrade.</p> <h1 id="upgraded-to-selenium-36">Upgraded to selenium 3.6</h1> <p>This version contains some backward incompatible changes, that’s why we decided to make a separate release.</p> <p>Thanks to <a href="https://github.com/ostap-oleksyn">Ostap Oleksyn</a> for <a href="https://github.com/selenide/selenide/pull/611">pull request 611</a>.</p> <p>By the way, we also upgraded to <code class="language-plaintext highlighter-rouge">guava 23.0</code> and <code class="language-plaintext highlighter-rouge">org.apache.httpcomponents:httpcore:4.4.7</code>.</p> <h1 id="fix-an-error-with-soft-asserts">Fix an error with soft asserts</h1> <p>Thanks to <a href="https://github.com/ostap-oleksyn">Ostap Oleksyn</a> for fixing <a href="https://github.com/selenide/selenide/issues/614">issue 614</a></p> <p><br /></p> <p>That’s it. This time the upgrade should be easy.</p> <h2 id="friendly-reminder">Friendly reminder</h2> <p>Welcome to the <a href="https://heisenbug-moscow.ru/">Heisenbug conference</a> in Moscow - 8-9.12.2017</p> <p>I will present 2 talks on it:</p> <ul> <li><a href="https://heisenbug-moscow.ru/talks/2017/msk/1su57z0to8qimacswsgksu/">Flaky tests</a></li> <li><a href="https://heisenbug-moscow.ru/talks/2017/msk/74qfnsvag4gcsi4sw8gyoi/">Selenide Puzzlers</a></li> </ul> <p><strong>Welcome to Russia!</strong></p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2017/10/08/selenide-4.8/ https://selenide.org/2017/10/08/selenide-4.8 2017-10-08T00:00:00+00:00 Released Selenide 4.7 <p>Good evening!</p> <p>We released Selenide 4.7 with the most wanted feature of the year. You’ll live the life now!</p> <p><br /></p> <h1 id="embedded-webdrivermanager">Embedded WebDriverManager</h1> <p>Now Selenide contains <a href="https://github.com/bonigarcia/webdrivermanager">WebDriverManager</a> - a library that can automatically download latest webdriver binary file. You don’t need to care about downloading <code class="language-plaintext highlighter-rouge">geckodriver.exe</code> or <code class="language-plaintext highlighter-rouge">chromedriver.exe</code> and adding it to <code class="language-plaintext highlighter-rouge">PATH</code>. Selenide will take care about it.</p> <p>There is one nuance. WebDriverManager will only work if:</p> <ol> <li>You use one of supported webdrivers: <code class="language-plaintext highlighter-rouge">chrome</code>, <code class="language-plaintext highlighter-rouge">edge</code>, <code class="language-plaintext highlighter-rouge">internet explorer</code>, <code class="language-plaintext highlighter-rouge">opera</code>, <code class="language-plaintext highlighter-rouge">phantomjs</code>, <code class="language-plaintext highlighter-rouge">marionette</code> or <code class="language-plaintext highlighter-rouge">gecko</code>.</li> <li>Your code hasn’t set system property <code class="language-plaintext highlighter-rouge">webdriver.chrome.driver</code>, <code class="language-plaintext highlighter-rouge">webdriver.edge.driver</code>, <code class="language-plaintext highlighter-rouge">webdriver.ie.driver</code>, <code class="language-plaintext highlighter-rouge">webdriver.opera.driver</code>, <code class="language-plaintext highlighter-rouge">phantomjs.binary.path</code> or <code class="language-plaintext highlighter-rouge">webdriver.gecko.driver</code>.</li> </ol> <p>If you use another webdriver (or a custom <code class="language-plaintext highlighter-rouge">WebDriverProvider</code>), WebDriverManager will not be used, and you will continue working as previously.</p> <p>If you still have some question, remember that the only true information source is the <a href="https://github.com/selenide/selenide/blob/master/src/main/java/com/codeborne/selenide/webdriver/">SOURCE CODE</a>!</p> <p>Thanks to Sergey Pirogov and Boris Osipov for <a href="https://github.com/selenide/selenide/pull/610">pull request 610</a>.</p> <p>See also issue <a href="https://github.com/selenide/selenide/issues/133">133</a> and <a href="https://github.com/selenide/selenide/issues/418">418</a></p> <h1 id="added-method-prompt">Added method <code class="language-plaintext highlighter-rouge">prompt()</code></h1> <p>As you probably know, there is 3 native modal dialogs in JavaScript: <code class="language-plaintext highlighter-rouge">alert</code>, <code class="language-plaintext highlighter-rouge">confirm</code> and <code class="language-plaintext highlighter-rouge">prompt</code>. Selenide supported <code class="language-plaintext highlighter-rouge">alert</code> and <code class="language-plaintext highlighter-rouge">confirm</code> from the very beginning, but not <code class="language-plaintext highlighter-rouge">prompt</code>.</p> <p>Now it’s supported too:</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">canSubmitPromptDialog</span><span class="o">()</span> <span class="o">{</span> <span class="err">$</span><span class="o">(</span><span class="s">"#login"</span><span class="o">).</span><span class="na">click</span><span class="o">();</span> <span class="n">prompt</span><span class="o">(</span><span class="s">"Please input your username"</span><span class="o">,</span> <span class="s">"Aegon Targaryen"</span><span class="o">);</span> <span class="n">prompt</span><span class="o">(</span><span class="s">"Please input your password"</span><span class="o">,</span> <span class="s">"qwerty"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#message"</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, Aegon Targaryen!"</span><span class="o">));</span> <span class="o">}</span> </code></pre></div></div> <p>Thanks to <a href="https://github.com/simple-elf">Anton Aftakhov</a> for <a href="https://github.com/selenide/selenide/pull/591">PR 591</a></p> <p><br /></p> <h1 id="added-path-for-html-file-to-selenide-error-message">Added path for html file to Selenide error message</h1> <p>One of the most convenient feature of Selenide is automatic taking of screenshot in case of error. When a test fails, Selenide takes a screenshot and adds its path to the error message. It’s incredibly convenient to read test report and open a screenshot with just one click. And you don’t even need to install any software like Thucydides, Allure, Report Portal etc. to have it. The most simple things are the most stable.</p> <p>But there is one more less-known feature.</p> <p>In addition to screenshot, Selenide also save a html source code of the page where error happened. Now we also added path to this file to Selenide error message.</p> <p>Thanks to <a href="https://github.com/hyunil-shin">hyunil-shin</a> for <a href="https://github.com/selenide/selenide/pull/590">PR 590</a>.</p> <p>Now Selenide error message will look like this:</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">text</span> <span class="err">'</span><span class="nc">Goodbye</span><span class="o">,</span> <span class="nc">Aegon</span> <span class="nc">Targaryen</span><span class="o">!</span><span class="err">'</span> <span class="o">{</span><span class="err">#</span><span class="n">message</span><span class="o">}</span> <span class="nl">Element:</span> <span class="err">'</span><span class="o">&lt;</span><span class="n">div</span> <span class="n">id</span><span class="o">=</span><span class="s">"message"</span><span class="o">&gt;</span><span class="nc">Hello</span><span class="o">,</span> <span class="nc">Aegon</span> <span class="nc">Targaryen</span><span class="o">!&lt;/</span><span class="n">div</span><span class="o">&gt;</span><span class="err">'</span> <span class="nl">Screenshot:</span> <span class="nl">file:</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">canSubmitPromptDialog</span><span class="o">/</span><span class="mf">1507061177250.0</span><span class="o">.</span><span class="na">png</span> <span class="nc">Page</span> <span class="nl">source:</span> <span class="nl">file:</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">canSubmitPromptDialog</span><span class="o">/</span><span class="mf">1507061177250.0</span><span class="o">.</span><span class="na">html</span> <span class="nl">Timeout:</span> <span class="mi">4</span> <span class="n">s</span><span class="o">.</span> </code></pre></div></div> <p><br /></p> <h1 id="fixed-concurrency-issue-with-screenshots-during-parallel-test-run">Fixed concurrency issue with screenshots during parallel test run</h1> <p>We fixed an old concurrency <a href="https://github.com/selenide/selenide/issues/570">issue 570</a> with screenshots.</p> <p>Thanks to <a href="https://github.com/jane-ryabchenko">Jane Riabchenko</a> for <a href="https://github.com/selenide/selenide/issues/595">PR 595</a></p> <p><br /></p> <h1 id="upgraded-to-selenium-java-353">Upgraded to selenium-java 3.5.3</h1> <p>We noticed that that selenium-java released version 3.6.0, and we are going to start using it in Selenide 4.8 which is going to be released soon.</p> <h1 id="upgraded-to-browsermob-core-215-and-littleproxy-110-beta-bmp-17">Upgraded to browsermob-core 2.1.5 (and littleproxy 1.1.0-beta-bmp-17)</h1> <p>It can only affect you if you download files via proxy server.</p> <h1 id="upgraded-htmlunit-from-224-to-227">Upgraded htmlunit from 2.24 to 2.27</h1> <p>Thanks to <a href="https://github.com/alexander-kotlyar">Alexander Kotlyar</a> for <a href="https://github.com/selenide/selenide/pull/609">PR 609</a>.</p> <h2 id="news">News</h2> <p>Welcome to the <a href="https://heisenbug-moscow.ru/">Heisenbug conference</a> in Moscow - 8-9.12.2017</p> <p>I will present 2 talks on it:</p> <ul> <li><a href="https://heisenbug-moscow.ru/talks/2017/msk/1su57z0to8qimacswsgksu/">Flaky tests</a></li> <li><a href="https://heisenbug-moscow.ru/talks/2017/msk/74qfnsvag4gcsi4sw8gyoi/">Selenide Puzzlers</a></li> </ul> <p><strong>Welcome to Russia!</strong></p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2017/09/30/selenide-4.7/ https://selenide.org/2017/09/30/selenide-4.7 2017-09-30T00:00:00+00:00 Released Selenide 4.6 <p>Good night!</p> <p>We released Selenide 4.6</p> <p><br /></p> <h1 id="method-shouldhaveexactvalue-foo---does-not-trim-leadingtrailing-spaces-anymore">Method <code class="language-plaintext highlighter-rouge">$.shouldHave(exactValue(" foo "))</code> does not trim leading/trailing spaces anymore</h1> <p>As you probably know, method <code class="language-plaintext highlighter-rouge">$.shouldHave(value(" foo "))</code> (which we all typically use) trims leading/trailing spaces in the given string. It’s convenient because web browsers also do so. But we recently found that method <code class="language-plaintext highlighter-rouge">exactValue()</code> also do it, and that’s not right.</p> <p>Assuming that you have <code class="language-plaintext highlighter-rouge">&lt;textarea value="Regression test description "&gt;&lt;/textarea&gt;</code> on a page, the check <code class="language-plaintext highlighter-rouge">$("textarea").shouldHave(exactValue("Regression test description "));</code> failed before this release. Not it will not.</p> <p>See. <a href="https://github.com/selenide/selenide/issues/573">issue 573</a></p> <p>Thanks to <a href="https://github.com/mseele">@mseele</a> for the <a href="https://github.com/selenide/selenide/pull/578">pull request</a>!</p> <h1 id="we-added-method-getsearchcriteria">We added method <code class="language-plaintext highlighter-rouge">$.getSearchCriteria()</code></h1> <p>Selenide always had a convenient method <code class="language-plaintext highlighter-rouge">$.toString()</code> - it prints actual description of a web element: tag, text, attributes. It’s very useful for logging and debugging. Bit it has one drawback: it calls webdriver methods to get those data, which can be slow sometimes.</p> <p>So we added method <code class="language-plaintext highlighter-rouge">$.getSearchCriteria()</code> that doesn’t call any webdriver methods, but just returns a locator.</p> <p>Simply said,</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">"h2"</span><span class="o">).</span><span class="na">toString</span><span class="o">(),</span> <span class="n">equalTo</span><span class="o">(</span><span class="s">"&lt;h2&gt;Dropdown list&lt;/h2&gt;"</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">"h2"</span><span class="o">).</span><span class="na">getSearchCriteria</span><span class="o">(),</span> <span class="n">equalTo</span><span class="o">(</span><span class="s">"h2"</span><span class="o">));</span> </code></pre></div></div> <p><br /></p> <h1 id="fixed-issue-528">Fixed <a href="https://github.com/selenide/selenide/issues/528">issue 528</a></h1> <p>Thanks to <a href="https://github.com/BorisOsipov">@BorisOsipov</a> for the <a href="https://github.com/selenide/selenide/pull/530">pull request</a>!</p> <h1 id="fixed-issue-484">Fixed <a href="https://github.com/selenide/selenide/issues/484">issue 484</a></h1> <p>Sometimes Selenide could throw such an error without screenshot:</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">valid</span><span class="o">-</span><span class="n">id</span><span class="o">.</span><span class="na">findBy</span><span class="o">(</span><span class="n">text</span> <span class="err">'</span><span class="no">INVALID</span><span class="o">-</span><span class="no">TEXT</span><span class="err">'</span><span class="o">)}</span> <span class="nl">Expected:</span> <span class="n">text</span> <span class="err">'</span><span class="mi">9802222</span><span class="o">-</span><span class="mi">99L</span><span class="no">X</span><span class="err">'</span> <span class="nl">Screenshot:</span> <span class="kc">null</span> <span class="nl">Timeout:</span> <span class="mi">0</span> <span class="n">ms</span><span class="o">.</span> </code></pre></div></div> <p>We fixed it.</p> <p><br /></p> <h1 id="fixed-running-ie-on-selenium-grid">Fixed running IE on selenium grid</h1> <p>(OMG, does somebody still use IE and Grid in 21st century?)</p> <p>See. <a href="https://github.com/selenide/selenide/issues/529">issue 529</a></p> <p>Thanks to <a href="https://github.com/BorisOsipov">@BorisOsipov</a> for the <a href="https://github.com/selenide/selenide/pull/531">pull request</a>!</p> <h2 id="news">News</h2> <p><br /></p> <ul> <li>http://www.devmedia.com.br/api-selenide-desenvolvimento-de-testes-funcionais-em-java/33680</li> <li>http://katrinatester.blogspot.com.ee/2017/05/three-styles-of-automation.html</li> <li>http://www.autotest.org.ua/selenide-quick-start-in-automation-testing/</li> <li>https://sweftt.com/en/2017/02/07/selenide-tests-maven-way/</li> <li>http://qiita.com/radiocat/items/7440c4f8da2101e13761</li> <li>http://codezine.jp/article/detail/10335?utm_source=dlvr.it&amp;utm_medium=twitter</li> <li>http://automation-remarks.com/2017/allure-without-annotations/</li> </ul> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2017/09/09/selenide-4.6/ https://selenide.org/2017/09/09/selenide-4.6 2017-09-09T00:00:00+00:00 Released Selenide 4.5 <p>Good evening!</p> <p>We released Selenide 4.5! This release is mainly dedicated to performance improvements of Selenide itself.</p> <p><br /></p> <h1 id="speed-up-method-setvalue">Speed up method <code class="language-plaintext highlighter-rouge">$.setValue()</code></h1> <p>Selenide had a cool feature… that nobody knew about. Method <code class="language-plaintext highlighter-rouge">$.setValue()</code> pretended to be smart so much it could set value not only to text inputs, but also to selects and radio buttons. The idea was that test should remain stable even if developers change element’s type (say, from <code class="language-plaintext highlighter-rouge">&lt;select&gt;</code> to <code class="language-plaintext highlighter-rouge">&lt;input type="radio"&gt;</code>).</p> <p>But this “smartness” is not for free: during every call to <code class="language-plaintext highlighter-rouge">$.setValue()</code> Selenide tried to detect element type, calling several webdriver methods for it. It took tens or hundreds of milliseconds.</p> <p>Since no one knew about it and did not use it, we decided to abandon this feature for the sake of performance. Now this “smart” behaviour of <code class="language-plaintext highlighter-rouge">$.setValue()</code> is <strong>disabled by default</strong>. If somebody should still need it, the following setting enables it:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">-</span><span class="nc">Dselenide</span><span class="o">.</span><span class="na">versatileSetValue</span><span class="o">=</span><span class="kc">true</span> </code></pre></div></div> <p>Though, there are simpler alternatives:</p> <ul> <li>either enable <code class="language-plaintext highlighter-rouge">-Dselenide.fastSetValue=true</code>,</li> <li>or use methods <code class="language-plaintext highlighter-rouge">$.selectOption()</code> and <code class="language-plaintext highlighter-rouge">$.selectRadio()</code>.</li> </ul> <p>Thanks to <a href="https://github.com/selenide/selenide/pull/518">Alexander Popov</a> for the improvement!</p> <p><br /></p> <h1 id="speed-up-collection-methods">Speed up collection methods</h1> <p>Selenide also pretended to be smart when working with collections. For example, the following 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">"tr"</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">7</span><span class="o">));</span> </code></pre></div></div> <p>would wait for some time (600 ms by default), even if collection already has 7 elements. Because “probably there will be loaded more elements soon, and test should fail then”.</p> <p>We also decided to abandon this feature for the sake of performance.</p> <p>See <a href="https://github.com/selenide/selenide/issues/549">pull request 549</a></p> <p><br /></p> <h1 id="added-methods-x-and-x">Added methods <code class="language-plaintext highlighter-rouge">$().$x()</code> and <code class="language-plaintext highlighter-rouge">$().$$x()</code></h1> <p>… for searching by XPath inside a web element.</p> <p>Now you can write 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">"table"</span><span class="o">).</span><span class="n">$x</span><span class="o">(</span><span class="s">".//tr"</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="s">"table"</span><span class="o">).</span><span class="err">$</span><span class="n">$x</span><span class="o">(</span><span class="s">".//tr"</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">5</span><span class="o">));</span> </code></pre></div></div> <p>Thanks to <a href="https://github.com/selenide/selenide/pull/533">Oleksii Cherevatyi</a> for this addition!</p> <p><br /></p> <h1 id="fix-support-for-opera-driver">Fix support for Opera driver</h1> <p>Thanks to <a href="https://github.com/selenide/selenide/commit/28233d6a88c9758c453629de1710818f28af6b84">Roman Marinsky</a> for the fix!</p> <p><br /></p> <h1 id="remove-unneeded-logs">Remove unneeded logs</h1> <p>Namely, we removed this message (when Selenide closes a webdriver):</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">INFO:</span> <span class="nc">Close</span> <span class="n">proxy</span> <span class="nl">server:</span> <span class="mi">24</span> <span class="o">-&gt;</span> <span class="kc">null</span> </code></pre></div></div> <p>Thanks to <a href="https://github.com/selenide/selenide/commit/03c781a3f644ec34782f04a28c08ec483b40143d">Andrew Zakordonets</a>!</p> <p><br /></p> <h1 id="upgraded-to-orglittleshootlittleproxy112">Upgraded to org.littleshoot:littleproxy:1.1.2</h1> <p>This applies only for those who uses option <code class="language-plaintext highlighter-rouge">Configuration.fileDownload=PROXY</code>.</p> <p><br /></p> <h1 id="upgraded-to-phantomjsdriver-143">Upgraded to phantomjsdriver 1.4.3</h1> <p><br /></p> <h1 id="added-lots-of-unit-tests-for-selenide-itself">Added lots of unit-tests for Selenide itself</h1> <p>This is my personal happiness.</p> <p>Andrew Zakordonets wanted to help the project and wrote a lot of missing unit-tests for Selenide itself. This is cool. Thank you Andrew!</p> <p><br /></p> <h2 id="news">News</h2> <p><br /></p> <h1 id="we-started-project-selenide-appium">We started project <code class="language-plaintext highlighter-rouge">selenide-appium</code></h1> <p>We created a separate project for better Selenide support for Appium framework: <a href="https://github.com/selenide/selenide-appium">github.com/selenide/selenide-appium</a></p> <p>This is only a beginning, but the project actually works. It’s already used in at least one real-life project for testing mobile applications.</p> <p><br /></p> <h1 id="we-added-more-projects-to-selenide-examples">We added more projects to Selenide examples</h1> <p>As you probably know, there is a series of mini-projects on github - <a href="https://github.com/selenide-examples">samples of using Selenide with different tools</a>. Recently we added couple of new samples:</p> <ul> <li><a href="https://github.com/selenide-examples/testcontainers">Selenide+TestContainers</a></li> <li><a href="https://github.com/selenide-examples/selenide-appium">Selenide+Appium</a></li> </ul> <p>We are working on new samples. Probably it will be Spring Boot, Allure 2 or something else. Feel free to send your own samples!</p> <p><br /></p> <h2 id="how-can-you-help-selenide">How can YOU help Selenide?</h2> <p>Dear friend! You can also help Selenide project. You don’t need to be a mature developer with 20 years of experience. No. Good will is the key for success.</p> <p>For example, we would be very appreciate if you:</p> <ul> <li>Review open <a href="https://github.com/selenide/selenide/pulls">pull requests</a> and comment if we should merge these changes to Selenide</li> <li>Review open <a href="https://github.com/selenide/selenide/issues">issues</a> and comment: <ul> <li>is it weird or reasonable question/feature request</li> <li>is it already done</li> <li>should we implement it</li> </ul> </li> <li>Write some missing documentation</li> <li>Write some blog post</li> <li>Write some missing tests for Selenide</li> <li>Add your own examples of using Selenide with other tools on <a href="https://github.com/selenide-examples">github.com/selenide-examples</a></li> <li>Find a volunteer designer to helps us with selenide.org (first of all, with mobile version)</li> </ul> <p>Any help is appreciated!</p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2017/06/26/selenide-4.5/ https://selenide.org/2017/06/26/selenide-4.5 2017-06-26T00:00:00+00:00 Released Selenide 4.3 <p>Hi all!</p> <p>Good news: we released Selenide 4.3</p> <p><br /></p> <h1 id="fix-method-find">Fix method <code class="language-plaintext highlighter-rouge">$$().find()</code></h1> <p>More exactly, it always could find elements correctly, but it gave a misleading error message in case element could not be found.</p> <p>Now it’s fixes and gives correct error message.</p> <p>See. <a href="https://github.com/selenide/selenide/pull/426">pull request 426</a></p> <p>Thanks to <a href="https://github.com/juliaviluhina">Julia Iluhina</a> for the fix!</p> <p><br /></p> <h1 id="fixed-page-object-fields-selenideelement-without-findby-annotation">Fixed page object fields <code class="language-plaintext highlighter-rouge">SelenideElement</code> without <code class="language-plaintext highlighter-rouge">@FindBy</code> annotation</h1> <p>Surprisingly, we found that Selenide could behave unexpectedly when you tried to use it unexpectedly. :)</p> <p>Let’s assume that you have a page object with field of type <code class="language-plaintext highlighter-rouge">SelenideElement</code> (without <code class="language-plaintext highlighter-rouge">@FindBy</code> annotation):</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">StartPage</span><span class="o">{</span> <span class="nc">SelenideElement</span> <span class="n">startPage</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#start-page"</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>This class is beautiful. It’s very simple and clean. It works out of the box without any fabrics and other utilities. You just need to create it: <code class="language-plaintext highlighter-rouge">StartPage page = new StartPage();</code> - and it works. This is just idea page object that is only possible in Selenide universe.</p> <p>But sometimes people still try to initialize it with <code class="language-plaintext highlighter-rouge">page</code> or some other factory methods, like this:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">StartPage</span> <span class="n">page</span> <span class="o">=</span> <span class="n">page</span><span class="o">(</span><span class="nc">StartPage</span><span class="o">.</span><span class="na">class</span><span class="o">);</span> </code></pre></div></div> <p>and here problems come… See <a href="https://github.com/selenide/selenide/pull/443">pull request 443</a></p> <p>But now it’s fixed. Thanks to <a href="https://github.com/SergeyPirogov">Sergei Pirogov</a> for the fix!</p> <p><br /></p> <h1 id="aligned-system-property-names-with-configuration-fields">Aligned system property names with Configuration fields</h1> <p>As you probably know, all Selenide settings can be set in two ways: either via system property or directly in code. But we found that some of them had different names. It was somewhat misleading.</p> <p>Now we aligned system properties names with Configuration fields. e.g. <code class="language-plaintext highlighter-rouge">Configuration.someProp</code> always has system property equivalent <code class="language-plaintext highlighter-rouge">selenide.someProp</code></p> <p>Old names still supported for backward compatibility.</p> <p><br /></p> <h1 id="deprecated-method-selenideselectradio">Deprecated method <code class="language-plaintext highlighter-rouge">Selenide.selectRadio</code></h1> <p>In Selenide, it was possible to select a radiobutton this way: <code class="language-plaintext highlighter-rouge">selectRadio(By.name("me"), "cat");</code> Now we marked this method as <code class="language-plaintext highlighter-rouge">@Deprecated</code>. You can use a “standard” Selenide method instead:</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">"me"</span><span class="o">)).</span><span class="na">selectRadio</span><span class="o">(</span><span class="s">"cat"</span><span class="o">);</span> </code></pre></div></div> <p><br /></p> <h1 id="created-constant-link-to-latest-javadoc">Created constant link to latest javadoc</h1> <p>Now the latest javadoc is always available at this link:</p> <center> <a href="https://selenide.org/javadoc/current/">selenide.org/javadoc/current/</a> </center> <p><br /></p> <h1 id="upgraded-dependencies">Upgraded dependencies</h1> <ul> <li>upgraded to browsermob-core:2.1.4</li> <li>upgraded to org.apache.httpcomponents:httpcore:4.4.6</li> <li>upgraded to guava:21.0</li> </ul> <h2 id="news">News</h2> <ul> <li>Historical moment! BrowserStack wrote a tutorial how to run Selenide tests in their cloud:<br /> <a href="https://www.browserstack.com/automate/selenide">BrowserStack+Selenide</a></li> <li>Yakiv Kramarenko workshop in San-Francisco: <a href="http://www.slideshare.net/yashaka/kiss-pageobjects-012017">Kiss PageObjects</a></li> <li>New article about Selenide in Japan: <a href="http://qiita.com/nyakome/items/207daf3050809c269e8e">I tried writing a test code with Selenide</a></li> <li>Selenide and GEB Comparision in Japan: <a href="http://qiita.com/PoohSunny/items/8641f24fa22e5b3beb16">Selenide as seen from Geb usage</a></li> <li>And one more tutorial in Japan: <a href="http://naruto-io.hatenablog.com/entry/2017/01/15/205751">Kotlin+Selenide</a></li> </ul> <p>Let’s upgrade!</p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2017/02/09/selenide-4.3/ https://selenide.org/2017/02/09/selenide-4.3 2017-02-09T00:00:00+00:00 Selenide 4.2.1 released <p><br /> Hi!</p> <p>This is a bugfix and enhancements release following “4.2(Browsers)”</p> <h2 id="fixed-usage-of-booleaninteger-capabilities-as-command-line-system-properties">Fixed usage of boolean/integer capabilities as command line system properties.</h2> <p>Since this release capabilities values are automatically converted to boolean/integer if transferred in SystemProperties, so for example the following parameters will be working fine</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-Dcapabilities.rotatable=true -Dcapabilities.elementScrollBehavior=1 </code></pre></div></div> <h2 id="firefox-support-for-firefoxprofile-preferences-over-command-line">Firefox: support for FirefoxProfile preferences over command line</h2> <p>Good news for users who need to transfer FirefoxProfile preferences to the WebDriver. <code class="language-plaintext highlighter-rouge">firefoxprofile.*</code> are now automatically processed by Selenide and transferred to Firefox and Marionette drivers.</p> <p>Example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-Dfirefoxprofile.browser.startup.homepage=http://www.google.com </code></pre></div></div> <p>Consult the list of available profile preferences with actual Firefox documentation.</p> <h2 id="chrome-support-for-chromeoptions-arguments-over-command-line">Chrome: support for ChromeOptions arguments over command line</h2> <p>Also chrome users benefit. ChromeOptions arguments are now applicable without need to extend classes. <code class="language-plaintext highlighter-rouge">chromeoptions.args=&lt;comma-separated-args&gt;</code> are automatically processed by Selenide and transferred to Chrome driver. Multiple arguments are separated by comma. At the same time Configuration.chromeSwitches and -Dselenide.chromeSwitches are deprecated as they only allowed a single argument.</p> <p>Example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-Dchromeoptions.args=--diagnostics,--disable-blink-features </code></pre></div></div> <p>Consult the list of available arguments with actual Chrome documentation.</p> <p>Best automation with 4.2.1!</p> <p><a href="https://github.com/selenide/selenide">Alexei Vinogradov &amp; Selenide Community</a></p> https://selenide.org/2017/01/26/selenide-4.2.1/ https://selenide.org/2017/01/26/selenide-4.2.1 2017-01-26T00:00:00+00:00 Selenide 4.2 released <p><br /> Hi!</p> <p>With 4.x we’ve just started to add useful features for communication with the constantly changing environment, and in this version we made a great step forward in supporting browsers.</p> <h2 id="support-of-legacy-firefox-driver-431">Support of legacy Firefox driver. <a href="https://github.com/selenide/selenide/issues/431">#431</a></h2> <p>As you may know, Firefox, starting with Firefox 48, is not supported by built-in Selenium driver (let’s name it legacy driver). You must use new marionette/gecko driver, which also works with the older version of Firefox, but, it is not yet that stable in many cases. We experienced many projects with a large number of test switched to use Firefox 45 ESR, with the legacy driver, instead of the newest Firefox, because of high costs for analysis and changes for broken tests with the new driver. In 4.2 you may choose, which driver to use for Firefox version &lt;=47</p> <p>Use <code class="language-plaintext highlighter-rouge">Configuration.browser="firefox"</code> (or System property <code class="language-plaintext highlighter-rouge">-Dselenide.browser=firefox</code>) to use legacy Firefox Driver (Firefox&lt;=47) built in Selenium.</p> <p>Use <code class="language-plaintext highlighter-rouge">Configuration.browser="gecko"</code> or <code class="language-plaintext highlighter-rouge">Configuration.browser="marionette"</code> (the same) to use geckodriver (any Firefox version). If driver is not in your executable path, you may need to setup the path in SystemProperty <code class="language-plaintext highlighter-rouge">webdriver.gecko.driver</code> (for example <code class="language-plaintext highlighter-rouge">-Dwebdriver.gecko.driver=/Users/mmeier/Downloads/geckodriver-0.11</code>)</p> <h2 id="microsoft-edge-support">Microsoft Edge support</h2> <p>We added new value for browser - <code class="language-plaintext highlighter-rouge">Configuration.browser="edge"</code>. Don’t forget to set the path to MicrosoftWebDriver.exe in SystemProperty <code class="language-plaintext highlighter-rouge">webdriver.edge.driver</code></p> <h2 id="better-support-for-https-site-with-invalid-certificates">Better support for https site with invalid certificates.</h2> <p>In this version we turn on a capability, that helps to avoid error with invalid SSL certificates for many cases. You don’t need to change anything in your test, the improvement is automatically active.</p> <h2 id="support-of-custom-capabilities-and-cloud-services-browserstack-saucelabs-etc-379">Support of custom capabilities and cloud services (BrowserStack, SauceLabs etc.) <a href="https://github.com/selenide/selenide/issues/379">#379</a></h2> <p>Until now, Selenide users did not have easy way to ask for custom capabilities for the browser. Starting from 4.2 System properties prefixed with <code class="language-plaintext highlighter-rouge">capabilities.*</code> automatically processed by Selenide as DesiredCapabilities. Among other things it helps to start your test by popular cloud service changing no line of your test code!</p> <p>As example, let’s start you tests at BrowserStack (of course, you must register and get username &amp; auth_key from the service first) under Windows 7 with Firefox 48 screen resolution 1680x1050. Just pass the parameters to your test runner:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-Dselenide.remote=https://&lt;username&gt;:&lt;auth_key&gt;@hub-cloud.browserstack.com/wd/hub -Dcapabilities.os=windows -Dcapabilities.os_version=7 -Dcapabilities.browser=firefox -Dcapabilities.browser_version=48.0 -Dcapabilities.resolution=1680x1050 </code></pre></div></div> <p>Please refer to the documentation of your cloud service about capabilities which should be set to get the desired environment.</p> <h2 id="other-changes">Other changes</h2> <ul> <li>Fixed <a href="https://github.com/selenide/selenide/issues/433">#433</a> bypass spawning local browser</li> <li>Added method <code class="language-plaintext highlighter-rouge">$.selectOptionContainingText(String)</code> <a href="https://github.com/selenide/selenide/issues/391">#391</a> - select option by substring.</li> <li>Fixed problem with screenshot of too large WebElements <a href="https://github.com/selenide/selenide/issues/378">#378</a></li> </ul> <p><br /> <br /></p> <p>Upgrade to 4.2 today!</p> <p><a href="https://github.com/selenide/selenide">Alexei Vinogradov &amp; Selenide Community</a></p> <p>ru.selenide.org</p> https://selenide.org/2016/12/30/selenide-4.2/ https://selenide.org/2016/12/30/selenide-4.2 2016-12-30T00:00:00+00:00 Released Selenide 4.1 <p>Achievement unlocked!</p> <p>This day came. We releases Selenide 4.1 that contain only your changes. Made by you. Your pull requests.</p> <p><br /></p> <h1 id="428-improve-byattribute-method-for-search-via-css-selectors">#428 Improve byAttribute method for search via css selectors</h1> <p>Method <code class="language-plaintext highlighter-rouge">byAttribute</code> (or shorter <code class="language-plaintext highlighter-rouge">by</code>) got more powerful. Before now, you could use it to find elements by attribute value:</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">by</span><span class="o">(</span><span class="s">"first-name"</span><span class="o">,</span> <span class="s">"john macclane"</span><span class="o">).</span><span class="na">click</span><span class="o">();</span> </code></pre></div></div> <p>Now you can use it to search element by substring in 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="n">by</span><span class="o">(</span><span class="s">"first-name*"</span><span class="o">,</span> <span class="s">"hn maccl"</span><span class="o">).</span><span class="na">click</span><span class="o">();</span> </code></pre></div></div> <p>by a starting of 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="n">by</span><span class="o">(</span><span class="s">"first-name*"</span><span class="o">,</span> <span class="s">"joh"</span><span class="o">).</span><span class="na">click</span><span class="o">();</span> </code></pre></div></div> <p>by an ending of 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="n">by</span><span class="o">(</span><span class="s">"first-name*"</span><span class="o">,</span> <span class="s">"clane"</span><span class="o">).</span><span class="na">click</span><span class="o">();</span> </code></pre></div></div> <p>and even by a word in 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="n">by</span><span class="o">(</span><span class="s">"first-name*"</span><span class="o">,</span> <span class="s">"john"</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/rmarinsky">Roman Marinsky</a> for <a href="https://github.com/selenide/selenide/pull/428">pull request 428</a></p> <p><br /> <br /></p> <h1 id="419-425-added-methods-textslist-and-exacttextslist">#419 #425 Added methods <code class="language-plaintext highlighter-rouge">texts(List)</code> and <code class="language-plaintext highlighter-rouge">exactTexts(List)</code></h1> <p>Before now, you could check texts in collection using varargs 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">"#row-1 td"</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">"pjotr"</span><span class="o">,</span> <span class="s">"iljich"</span><span class="o">,</span> <span class="s">"chajkovskij"</span><span class="o">)));</span> </code></pre></div></div> <p>Now you can also pass list instead of varargs:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">List</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="n">expected</span> <span class="o">=</span> <span class="n">asList</span><span class="o">(</span><span class="s">"pjotr"</span><span class="o">,</span> <span class="s">"iljich"</span><span class="o">,</span> <span class="s">"chajkovskij"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#row-1 td"</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="n">expected</span><span class="o">)));</span> </code></pre></div></div> <p>Thanks to</p> <ul> <li><a href="https://github.com/yashaka">Yakov Kramarenko</a> for the <a href="https://github.com/selenide/selenide/issues/419">suggestion</a>, and</li> <li><a href="https://github.com/pavelsmolensky">Pavel Smolensky</a> for the <a href="https://github.com/selenide/selenide/pull/425">pull request</a>.</li> </ul> <p><br /></p> <h1 id="improve-support-for-gecko-marionette-driver">Improve support for gecko (marionette) driver</h1> <p>Now instead of</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">new</span> <span class="nc">MarionetteDriver</span><span class="o">(</span><span class="n">capabilities</span><span class="o">);</span> </code></pre></div></div> <p>Selenide initializes webdriver like this:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">DesiredCapabilities</span> <span class="n">capabilities</span> <span class="o">=</span> <span class="n">createFirefoxCapabilities</span><span class="o">(</span><span class="n">proxy</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">"marionette"</span><span class="o">,</span> <span class="kc">true</span><span class="o">);</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">FirefoxDriver</span><span class="o">(</span><span class="n">capabilities</span><span class="o">);</span> </code></pre></div></div> <p>I still don’t understand if (and why) it’s better, but we are working on Marionette driver support anyway.</p> <p><br /></p> <h1 id="upgraded-dependencies">Upgraded dependencies:</h1> <ul> <li>selenium-java 3.0.1</li> <li>htmlunit-driver 2.23.2</li> <li>gson 2.8.0</li> <li>guava 20.0</li> <li>httpcore:4.4.5</li> </ul> <p><br /></p> <h2 id="news">News</h2> <ul> <li>Blogs post about Selenide <a href="http://qiita.com/shimashima35/items/a437f0ed080a9ba71b72">in Japanese</a></li> <li>Presentation about Selenide <a href="http://backpaper0.github.io/ghosts/try-selenide/index.html#1">in Japanese</a></li> <li><a href="https://github.com/backpaper0/selenide-demo">Selenide demo</a> with Redmine and Docker</li> </ul> <p>I cannot read Japanese, but look how beautiful those page objects are!</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">AdminPage</span> <span class="kd">extends</span> <span class="nc">AbstractPage</span> <span class="o">{</span> <span class="nd">@FindBy</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"commit"</span><span class="o">)</span> <span class="kd">public</span> <span class="nc">SelenideElement</span> <span class="n">デフォルト設定をロード</span><span class="o">;</span> <span class="nd">@FindBy</span><span class="o">(</span><span class="n">css</span> <span class="o">=</span> <span class="s">".users"</span><span class="o">)</span> <span class="kd">public</span> <span class="nc">SelenideElement</span> <span class="n">ユーザー</span><span class="o">;</span> <span class="o">}</span> </code></pre></div></div> <p>And more beauty in Japanese:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kt">void</span> <span class="n">添付ファイル数は</span><span class="o">(</span><span class="kt">int</span> <span class="n">size</span><span class="o">)</span> <span class="o">{</span> <span class="n">添付ファイル一覧</span><span class="o">.</span><span class="na">shouldHaveSize</span><span class="o">(</span><span class="n">size</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>Isn’t it nice?</p> <p><br /> <br /></p> <p>Selenide 4.2 will be released very soon.</p> <p>Let’s upgrade!</p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2016/12/01/selenide-4.1/ https://selenide.org/2016/12/01/selenide-4.1 2016-12-01T00:00:00+00:00 Selenide presentation on TopConf 2016 <p>Good evening!</p> <p>I recently <a href="http://topconf.com/tallinn-2016/trackevent/selenide-concise-ui-tests-in-java/">presented Selenide</a> on TopConf conference in Tallinn.</p> <p>Video:</p> <iframe src="//www.youtube.com/embed/hHwFIONnVRs" width="960" height="569" frameborder="0"></iframe> <p>And my presentation:</p> <div class="wrapper-content center"> <iframe src="https://docs.google.com/presentation/d/1kH4tQuZujMYgW_gcHI0-ekNxV7dGspZbNIb4DVUgURs/embed?start=false&amp;loop=false&amp;delayms=3000" frameborder="0" width="960" height="569" allow="fullscreen" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe> </div> <p><br /></p> <p>Andrei Solntsev</p> <p>selenide.org</p> https://selenide.org/2016/11/16/selenide-on-topconf/ https://selenide.org/2016/11/16/selenide-on-topconf 2016-11-16T00:00:00+00:00 A wrapper or pure Selenium? <p>There is a popular opinion that using Selenide is not serious for a “true” automation engineer.<br /> A real engineer should use pure Selenium to understand how it works inside.</p> <p>And that’s why it’s bad.</p> <h2 id="a-story-of-true-driver">A story of true driver</h2> <p>Imagine: you are in a great hurry to get on the plane. Get in a taxi, say: “Urgently to the airport!” And the taxi driver tells you: now I will put the motor on the frame, fasten the wheels, fill up the fuel - and we will go!</p> <p>You freak out, but ok, since this is the accepted practice in this industry, then you have to wait.</p> <h3 id="coverage">Coverage</h3> <p>You wait five minutes, glancing nervously at your watch. You say: “Well, are we going already?” And you hear: “Yes, I have already screwed half the nuts in the motor.” And proudly adds: “I have 70% nut coverage!”</p> <h3 id="reports">Reports</h3> <p>After another five minutes, you nervously ask again and hear: “Yes, yes, everything is cool! The seats are almost set.” And he proudly adds: “You can see the report with pictures of the steps taken.”</p> <h3 id="but-if-something-should-happen">But if something should happen</h3> <p>You swear loudly and say, “What the hell? Why don’t we just get in the car and drive?”<br /> And the driver says: “Let the junior engineers drive factory cars.<br /> True drivers need to know how it works inside.”<br /> And proudly adds: “But if something should happen, I can figure out what’s broken.”</p> <h3 id="ready-solutions">Ready solutions</h3> <p>Needless to say, five minutes after the start of the movement, spark plug gets broken.<br /> The driver says: “Yes, this is a typical problem. I know what to do. I’ve had it.<br /> I am going to add a couple of sleep’s.”</p> <p>Then the wheel falls off, and the dude with undisguised pride says that he faced this problem too, and he has a ready-made solution in his garage, which he stole from a previous project.</p> <p>Yeah guys, this is the dude who prefers pure Selenium.</p> <h3 id="sit-and-drive">Sit and drive</h3> <p>Sooner or later, you give up and catch another car, in which everything is ready, configured and filled.<br /> It just rides. And the driver just takes you to the airport. In time.</p> <p>This is an engineer using Selenide.</p> <h2 id="so-what-shouldnt-we-learn-selenium">So what, shouldn’t we learn Selenium?</h2> <p>I hope you find it funny at this place.<br /> Probably some of you feel offended. And this is good! The more offensive the better.<br /> The more likely it will make you wonder where our industry is heading.</p> <p>When the resentment subsides, you should have a natural question.</p> <ul> <li>So what, we should only use the ready-made solutions without learning their internals?</li> <li>Shouldn’t a true driver know how the engine works and where to fill the oil?</li> <li>Shouldn’t a true driver be able to fix a car if it suddenly breaks down in the middle of the road?</li> </ul> <p><em>If everyone uses only ready tools, we will soon have no real specialists left!</em></p> <p>My answer is:</p> <h3 id="of-course-learn">Of course, learn!</h3> <p>Sure, we should learn. We must learn. It’s absolutely necessary.</p> <p><em>A bad QA engineer is the one who does not dream of writing his own framework.</em></p> <p><strong>But not at the expense of the client!</strong></p> <p>Disassemble the engine. Dig into the pieces of iron. Play with solid oil. But - in your garage. In trainee garage. <br /> But being at work - be so kind to do the work. Not your training. <br /> When you have free time and energy, improve yourself.<br /> When a client needs to go to the airport, take them to the airport and use the most effective tools for this.</p> <p>That is Selenide, yes.</p> <p><br /> <br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2016/10/20/selenide-vs-pure-selenium/ https://selenide.org/2016/10/20/selenide-vs-pure-selenium 2016-10-20T00:00:00+00:00 Released Selenide 4.0 <p>Hi all!</p> <p>It happened, finally!</p> <p>After 3-years-length waiting, Selenium WebDriver 3.0 was released.</p> <p>And we released Selenide 4.0.</p> <h2 id="what-changed">What changed?</h2> <p>Actually nothing should change for you. They just cleared some legacy garbage from selenium (that was never used by Selenide).</p> <p>What is actually important that Selenide now requires Java 8.</p> <p>Hurrra!!! Now QA world will finally move to Java 8 and lambdas!</p> <h2 id="can-i-get-more-details">Can I get more details!</h2> <p>Sure. Here is a <a href="https://seleniumhq.wordpress.com/2016/10/13/selenium-3-0-out-now/">list of Selenium WebDriver 3.0.0 changes</a>.</p> <p><br /></p> <h2 id="news">News</h2> <ul> <li>About another major upgrade for unit-tests: <a href="http://asolntsev.github.io/en/2016/10/11/mockito-2.1/">Migration to Mockito 2.1</a></li> <li>About old good things: <a href="http://asolntsev.github.io/en/2016/10/03/spring-boobs/">Spring boobs</a></li> <li>Great <a href="http://testingchallenges.thetestingmap.org/">portal for developing your testing skills</a></li> </ul> <p><br /> <br /></p> <p>Let’s upgrade!</p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2016/10/15/selenide-4.0/ https://selenide.org/2016/10/15/selenide-4.0 2016-10-15T00:00:00+00:00 Released Selenide 3.11 <p>Good evening!</p> <p>We released Selenide 3.11! This is the last release in 3.x series. The last working on Java 7 and Selenium WebDriver 2.x</p> <p>The following is Selenide 4.x: Selenium WebDriver 3.x and Java 8.</p> <p>So, what we have in Selenide 3.11:</p> <h2 id="added-condition-checked">Added condition <code class="language-plaintext highlighter-rouge">checked</code></h2> <p>Now you can write readable test for checkbox:</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">"#i-agree"</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">checked</span><span class="o">);</span> </code></pre></div></div> <p>Before now, you had to write <code class="language-plaintext highlighter-rouge">$.shouldBe(selected)</code> which is not pretty clear.</p> <p><strong>Check</strong>box should be <strong>checked</strong>.</p> <p>See <a href="https://github.com/selenide/selenide/issues/416">issue 416</a></p> <h2 id="optimization-of-getmessage">Optimization of <code class="language-plaintext highlighter-rouge">getMessage()</code></h2> <p>There is a strange behaviour in Selenium. When you get any exception from WebDriver (any subclass of <code class="language-plaintext highlighter-rouge">SeleniumException</code>), its method <code class="language-plaintext highlighter-rouge">getMessage()</code> is called.</p> <p>And method <code class="language-plaintext highlighter-rouge">SeleniumException.getMessage()</code> tries to be too smart. It tries to add IP and host name of current machine to the error message. And detecting host name can be very slow.</p> <p>And it appeared that Selenide does call this method multiple times.</p> <p>I believe that <code class="language-plaintext highlighter-rouge">getMessage()</code> should <strong>not</strong> this. It’s not its business. But all we can do is just to optimize <code class="language-plaintext highlighter-rouge">getMessage()</code> calls, so that Selenide would not call this method multiple times.</p> <p>So we did it.</p> <p>See <a href="https://github.com/selenide/selenide/issues/415">issue 415</a></p> <p><br /> <br /></p> <p>Waiting for Selenium 3.0…</p> <p><br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2016/10/14/selenide-3.11/ https://selenide.org/2016/10/14/selenide-3.11 2016-10-14T00:00:00+00:00 BDD with Selenide <p>Hi!</p> <p>People often ask if they can use BDD with Selenide.</p> <p>Short answer: Yes, you can!</p> <p>There is plenty of BDD tools in Java and Python. You can use any of them with Selenide. Some working examples: Selenide + Cucumber: https://github.com/selenide-examples/cucumber/tree/master/src/test/resources/org/selenide/examples/cucumber</p> <p>Selenide + JBehave: https://gist.github.com/mp911de/009ea539271da0633c59</p> <p>Selenide + GEB: https://github.com/selenide-examples/geb-maven-tutorial/blob/master/src/test/groovy/stepdefs/IndexStepDefs.groovy</p> <p>Selenide + Gauge: https://github.com/selenide-examples/GaugeSelenideExample/blob/master/specs/example.spec You can find a whole book here full of examples with Selenide, JBehave and Cucumber: https://www.amazon.com/Test-Driven-Java-Development-Viktor-Farcic/dp/1783987421?tag=viglink12630-20</p> <p>P.S. I personally don’t value BDD really much. I think it’s a nice idea, but it doesn’t really work. Business stakeholders do not really write executable specifications.</p> <p><br /> <br /></p> <p>Let’s upgrade!</p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2016/09/28/bdd-with-selenide/ https://selenide.org/2016/09/28/bdd-with-selenide 2016-09-28T00:00:00+00:00 Released Selenide 3.10 <p>Hi!</p> <p>We released Selenide 3.10!</p> <h2 id="proxy-server-is-disabled-by-default">Proxy server is disabled by default</h2> <p>It’s I am sad to say this, but it seems that the experiment with a proxy server has not yet succeeded.</p> <p>There is a problem with the “new way” of downloading files using Selenide built-in proxy server. It works for all my projects, but some folks reported that it doesn’t work for them. I still don’t know exactly the problem and its causes. Probably those who use Selenium Grid experience this problem.</p> <p>Anyway, now <a href="https://github.com/selenide/selenide/issues/402">we reverted</a> default downloading mechanism to <code class="language-plaintext highlighter-rouge">HTTPGET</code>. If you need to use proxy server, enable it via system property:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-Dselenide.fileDownload=PROXY </code></pre></div></div> <p>Or directly in your code:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Configuration</span><span class="o">.</span><span class="na">fileDownload</span> <span class="o">=</span> <span class="no">PROXY</span><span class="o">;</span> </code></pre></div></div> <p>By the way, we fixed <a href="https://github.com/selenide/selenide/issues/393">issue 393</a>: Selenide will not even try to run proxy server until <code class="language-plaintext highlighter-rouge">fileDownload=PROXY</code> is set.</p> <h2 id="added-support-for-multiple-selects">Added support for multiple selects</h2> <p>There are dropdown lists that allowing selecting multiple options (<code class="language-plaintext highlighter-rouge">&lt;select multiple&gt;</code>). Now it’s easy to select multiple options in Selenide with just one command:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">select</span><span class="o">.</span><span class="na">selectOption</span><span class="o">(</span><span class="s">"Margarita"</span><span class="o">,</span> <span class="s">"Theodor Woland"</span><span class="o">);</span> <span class="c1">// by test</span> <span class="n">select</span><span class="o">.</span><span class="na">selectOption</span><span class="o">(</span><span class="mi">0</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="c1">// by index</span> <span class="n">select</span><span class="o">.</span><span class="na">selectOptionByValue</span><span class="o">(</span><span class="s">"cat"</span><span class="o">,</span> <span class="s">"woland"</span><span class="o">);</span> <span class="c1">// by value</span> </code></pre></div></div> <p>We also added a method for getting all selected options:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">select</span><span class="o">.</span><span class="na">getSelectedOptions</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">"Margarita"</span><span class="o">,</span> <span class="s">"Theodor Woland"</span><span class="o">));</span> </code></pre></div></div> <p>See <a href="https://github.com/selenide/selenide/issues/400">issue 400</a></p> <h2 id="now-you-can-print-report-only-for-failed-tests">Now you can print report only for failed tests</h2> <p>As you probably know, in Selenide you can print <a href="https://selenide.org/2015/11/30/selenide-2.25">report of all executed steps </a>.</p> <p>Now you can configure if it should be printed only for failed tests. Or only for succeeded tests. Or always.</p> <p>For JUnit:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nd">@Rule</span> <span class="kd">public</span> <span class="nc">TestRule</span> <span class="n">report</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">TextReport</span><span class="o">().</span><span class="na">onFailedTest</span><span class="o">(</span><span class="kc">true</span><span class="o">).</span><span class="na">onSucceededTest</span><span class="o">(</span><span class="kc">false</span><span class="o">);</span> </code></pre></div></div> <p>For TestNG:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nd">@Listeners</span><span class="o">(</span><span class="nc">TextReport</span><span class="o">.</span><span class="na">class</span><span class="o">)</span> <span class="kd">public</span> <span class="kd">class</span> <span class="nc">GoogleTestNGTest</span> <span class="o">{</span> <span class="nd">@BeforeMethod</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setUp</span><span class="o">()</span> <span class="o">{</span> <span class="nc">TextReport</span><span class="o">.</span><span class="na">onSucceededTest</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span> <span class="nc">TextReport</span><span class="o">.</span><span class="na">onFailedTest</span> <span class="o">=</span> <span class="kc">true</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/408">issue 408</a></p> <h2 id="fixed-bug-with-parsing-http-header-content-disposition-containing-encoding">Fixed bug with parsing http header <code class="language-plaintext highlighter-rouge">Content-Disposition</code> containing encoding</h2> <p>Now Selenide uses correct file name even if header <code class="language-plaintext highlighter-rouge">Content-Disposition</code> contains encoding:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Content-Disposition: filename=Prices.csv;charset=UTF-8 </code></pre></div></div> <p>See. <a href="https://github.com/selenide/selenide/issues/398">issue 398</a></p> <h2 id="fixed-bug-401-selenide-swallows-exception-in-some-cases">Fixed bug 401: “Selenide swallows exception in some cases”</h2> <p>Never ever write <code class="language-plaintext highlighter-rouge">catch (Throwable)</code>. Never!</p> <p>See. <a href="https://github.com/selenide/selenide/issues/401">issue 401</a></p> <h2 id="method-openurl-now-works-for-url-in-upper-case">Method <code class="language-plaintext highlighter-rouge">open(url)</code> now works for URL in upper case</h2> <p>It’s weird, but sometimes people want to enter url in upper case. And they found that Selenide could not open such urls. Ups.</p> <p>Now we fixed it: <a href="https://github.com/selenide/selenide/issues/407">issue 407</a></p> <h2 id="uncommented-one-old-test">Uncommented one old test</h2> <p>See. <a href="https://github.com/selenide/selenide/issues/379">issue 379</a></p> <p><br /></p> <h2 id="news">News</h2> <ul> <li>Test mobile? Now it’s easy! <a href="https://github.com/selenide-examples/selenide-appium">Examples of Selenide+Appium</a></li> </ul> <p>Yes, you can use Selenide for testing mobile applications!</p> <p><br /> <br /></p> <p>Let’s upgrade!</p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2016/09/26/selenide-3.10/ https://selenide.org/2016/09/26/selenide-3.10 2016-09-26T00:00:00+00:00 Released Selenide 3.9.2 <p>Good evening!</p> <p>We released Selenide 3.9.2!</p> <p><br /> <br /></p> <h2 id="you-can-download-files-differently">You can download files differently</h2> <p>As you know, we changed a way of downloading files in Selenide 3.9. We got quite different feedback: some folks reported that new way works for cases where old way didn’t work, while others reported that the new way doesn’t work for cases where the old way worked.</p> <p>That’s why we decided to provide users a choice.</p> <p>Now you can choose how to download files.</p> <h3 id="new-way---proxy">“New” way - PROXY</h3> <p>This way is enabled by default.</p> <p>It downloads files using selenide’s own embedded proxy server.</p> <h4 id="pros">Pros:</h4> <ul> <li>This is better because it’s more universal: it not only works with <code class="language-plaintext highlighter-rouge">&lt;a href</code> elements, but with any other elements too. Actually it doesn’t depend on web elements at all. It just intercepts all server responses containing files.</li> </ul> <h4 id="cons">Cons:</h4> <ul> <li>If you run your own WebDriver instance (and add it to Selenide using method <code class="language-plaintext highlighter-rouge">setWebDriver()</code>), it knows nothing about selenide proxy server, which cannot intercept server responses. We will think how to improve this situation.</li> </ul> <h3 id="old-way---httpget">“Old” way - HTTPGET</h3> <p>If you need to use the “old” way, just add system property <code class="language-plaintext highlighter-rouge">-Dselenide.fileDownload=HTTPGET</code>. Or directly in the code:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Configuration</span><span class="o">.</span><span class="na">fileDownload</span> <span class="o">=</span> <span class="no">HTTPGET</span><span class="o">;</span> </code></pre></div></div> <h4 id="pros-1">Pros:</h4> <ul> <li>It works independently from selenide proxy server.</li> </ul> <h4 id="cons-1">Cons:</h4> <ul> <li>It works only with <code class="language-plaintext highlighter-rouge">&lt;a href</code> elements, and can execute only GET requests.</li> <li>It may not work if the machine that runs your tests doesn’t have access to a server from which files are downloaded.</li> </ul> <p>Now you don’t have excuse not to upgrade to Selenide 3.9.2</p> <h2 id="statistics-update">Statistics update</h2> <p>Selenide download statistics for August 2016:</p> <center> <img src="/images/2016/09/selenide.downloads.png" width="800" /> </center> <p><br /> <br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2016/09/03/selenide-3.9.2/ https://selenide.org/2016/09/03/selenide-3.9.2 2016-09-03T00:00:00+00:00 Released Selenide 3.9.1 <p>Hi all!</p> <p>We released Selenide 3.9.1!</p> <p><br /> <br /></p> <h3 id="killer-feature-selenide-can-now-download-any-files-from-anywhere">Killer feature! Selenide can now download <strong>any</strong> files. From anywhere.</h3> <p>We planned to do it for a long, and now it finally happened! Those endless problems with downloading files in Selenium are over. Now it’s easy. Just one simple method for all cases:</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">"input#submit"</span><span class="o">).</span><span class="na">download</span><span class="o">();</span> </code></pre></div></div> <p>Actually method <code class="language-plaintext highlighter-rouge">download</code> existed in Selenide for a long time. But it could only download files from links with href attribute: <code class="language-plaintext highlighter-rouge">&lt;a href</code>.</p> <p>It was good, but not enough in some cases. For example:</p> <ul> <li>Button click submits a form - resulting in downloading a file</li> <li>Button click opens a PDF in new tab (“inline” mode - browser built-in PDF viewer)</li> </ul> <p>Now Selenide can download any files in all these cases. To make it possible, Selenide run a built-in proxy server (namely, <a href="https://github.com/lightbody/browsermob-proxy">BrowserMobProxy</a>).</p> <h4 id="how-downloading-works">How downloading works:</h4> <ol> <li>Test executes command <code class="language-plaintext highlighter-rouge">$("selector").download();</code></li> <li>Selenide activate the proxy server</li> <li>Selenide clicks the element</li> <li>Proxy server catches all server responses that contain http header <code class="language-plaintext highlighter-rouge">Content-Disposition</code>. Selenide extracts file name from this header, and saves corresponding file to folder <code class="language-plaintext highlighter-rouge">build/reports/tests</code>.</li> <li>Selenide waits (up to 4 seconds) until at least one file gets downloaded.</li> <li>Method <code class="language-plaintext highlighter-rouge">$.download()</code> return the first downloaded file.</li> <li>If some new tabs/windows has been opened meanwhile (during steps 1-6), Selenide will closes all of them. It’s needed for cases when PDF gets opened in a new tab.</li> </ol> <p>See <a href="https://github.com/selenide/selenide/issues/196">issue #196</a> and <a href="https://github.com/selenide/selenide/pull/267">pull request #267</a>.</p> <p>Huge thanks to <a href="https://github.com/dimand58">Dmitrii Demin</a> for his commitment to this feature, suggestions and discussions!</p> <h3 id="selenide-proxy-server">Selenide proxy server</h3> <p>Yes, now Selenide runs its own proxy server when running tests.</p> <p>In future we can use it for implementing other useful features. For example, we could check http statuses of pages and other resources. We could inject own code into pages etc.</p> <p>Please share your ideas, let’s brainstorm!</p> <h3 id="warning-about-too-large-requestsresponses">Warning about too large requests/responses</h3> <p>Now Selenide tracks size of requests and responses. If some of them exceeded 2 MB, Selenide will write a warning in logs.</p> <p>This is experimental feature. Please share your experience with it. Did you get new knowledge? Did you have some problems with it?</p> <p>See <a href="https://github.com/selenide/selenide/issues/383">issue #383</a></p> <h3 id="now-softasserts-listener-works-correctly-with-testng">Now <code class="language-plaintext highlighter-rouge">SoftAsserts</code> listener works correctly with TestNG</h3> <p>We found that <code class="language-plaintext highlighter-rouge">TestNG</code> is a bad boy. Really, it has some really weird issues. For example, if you declare <code class="language-plaintext highlighter-rouge">@Listeners(SoftAsserts.class)</code> in <strong>some</strong> of your test classes, TestNG will automatically apply <code class="language-plaintext highlighter-rouge">SoftAsserts</code> listener to <strong>all</strong> of your tests. Unbelievable!</p> <p>We created a workaround for this problem. Now <code class="language-plaintext highlighter-rouge">SoftAsserts</code> listener will check if the current test (or its parent) really declares annotation <code class="language-plaintext highlighter-rouge">@Listeners(SoftAsserts.class)</code>.</p> <p>See <a href="https://github.com/selenide/selenide/issues/384">issue #384</a></p> <h3 id="now-softasserts-testng-listener-ignores-tests-with-attribute-expectedexceptions">Now <code class="language-plaintext highlighter-rouge">SoftAsserts</code> TestNG listener ignores tests with attribute “expectedExceptions”</h3> <p>Let me describe the problem. Suppose you have a test:</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">SoftAsserts</span><span class="o">.</span><span class="na">class</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="nd">@Test</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">myCheckA</span><span class="o">()</span> <span class="o">{...}</span> <span class="nd">@Test</span><span class="o">(</span><span class="n">expectedExceptions</span> <span class="o">=</span> <span class="o">...)</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">myCheckB</span><span class="o">()</span> <span class="o">{...}</span> <span class="o">}</span> </code></pre></div></div> <p>Obviously, <code class="language-plaintext highlighter-rouge">SoftAsserts</code> mode should be used in method <code class="language-plaintext highlighter-rouge">myCheckA</code>, but <strong>should not</strong> be used in method <code class="language-plaintext highlighter-rouge">myCheckB</code>. Because <code class="language-plaintext highlighter-rouge">myCheckB</code> expects some specific error, and <code class="language-plaintext highlighter-rouge">SoftAsserts</code> would break the whole flow if it caught the error.</p> <p>See <a href="https://github.com/selenide/selenide/issues/372">issue #372</a></p> <h3 id="fixed-bug-with-basic-auth-in-ie-browser">Fixed bug with basic auth in IE browser</h3> <p>See <a href="https://github.com/selenide/selenide/issues/366">issue #366</a> and <a href="https://github.com/selenide/selenide/pull/369">pull request #369</a></p> <p>Thanks to <a href="https://github.com/simple-elf">Anton Aftakhov</a> for this pull request!</p> <h3 id="upgraded-to-gson-27">Upgraded to gson 2.7</h3> <p>Selenium uses quite old gson 2.3.1, but sometimes you want to use a newer one.</p> <p><br /></p> <h2 id="news">News</h2> <ul> <li>My interview on popular russian IT portal: <a href="https://habrahabr.ru/company/jugru/blog/308528/">About legacy code</a></li> <li><a href="http://asolntsev.github.io/ru/2016/08/05/why-programmer-cannot-be-true-tester/">Why programmer cannot be a good tester</a></li> <li>Released <a href="http://automation-remarks.com/videorecorder-java/">video-recorder 1.0.8</a> - a really cool thing! Now production ready.</li> </ul> <p><br /> <br /></p> <p>Let’s upgrade!</p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2016/08/27/selenide-3.9.1/ https://selenide.org/2016/08/27/selenide-3.9.1 2016-08-27T00:00:00+00:00 Released Selenide 3.8 <p>Good night!</p> <p>We released Selenide 3.8! It fixes some small issues and introduces small but useful features.</p> <p><br /></p> <h3 id="fixed-file-uploading-on-remote-browsers-in-grid">Fixed file uploading on remote browsers in Grid</h3> <p>Thanks to <a href="https://github.com/vinogradoff">Alexei Vinogradov</a> for fixing remote upload!</p> <h3 id="now-you-can-disable-automatic-creating-of-html-files">Now you can disable automatic creating of *.html files</h3> <p>When your test fails, Selenide automatically saves 2 files:</p> <ol> <li>Screenshot - *.png file</li> <li>Page source code - *.html file</li> </ol> <p>But sometimes people don’t want to save *.html files. For example, in case of single page application the page source contains html code of all application pages. Thus it’s too big and useless.</p> <p>Now you can disable saving html files. As usually, via system property:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> mvn <span class="nb">test</span> <span class="nt">-Dselenide</span>.savePageSource<span class="o">=</span><span class="nb">false</span> </code></pre></div></div> <p>or directly in your 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">savePageSource</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span> </code></pre></div></div> <p>Thanks to <a href="https://github.com/BorisOsipov">Boris Osipov</a> for this <a href="https://github.com/selenide/selenide/pull/359">pull request</a>!</p> <h3 id="added-method-draganddroptowebelement">Added method <code class="language-plaintext highlighter-rouge">$.dragAndDropTo(WebElement)</code></h3> <p>Until now, Selenide had only method <code class="language-plaintext highlighter-rouge">$.dragAndDropTo(String)</code>, where string parameter is CSS selector of target element. But sometimes you want to define target element in another way.</p> <p>Now you can use the new method <code class="language-plaintext highlighter-rouge">$.dragAndDropTo(WebElement)</code>. For example:</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="err">$</span><span class="o">(</span><span class="n">byText</span><span class="o">(</span><span class="s">"Drop here"</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">"#from"</span><span class="o">).</span><span class="na">dragAndDropTo</span><span class="o">(</span><span class="n">target</span><span class="o">);</span> </code></pre></div></div> <p>See <a href="https://github.com/selenide/selenide/issues/355">issue #355</a></p> <h3 id="now-testng-annotations-simplereport-and-softasserts-are-thread-safe">Now TestNG annotations <code class="language-plaintext highlighter-rouge">SimpleReport</code> and <code class="language-plaintext highlighter-rouge">SoftAsserts</code> are thread-safe</h3> <p>If you use annotations <code class="language-plaintext highlighter-rouge">SimpleReport</code> or <code class="language-plaintext highlighter-rouge">SoftAsserts</code> and TestNG framework, and run tests in parallel, you could see an empty report sometimes. Or you could get <code class="language-plaintext highlighter-rouge">ConcurrentModificationException</code> time-to-time.</p> <p>It appeared that TestNG is bad boy. Just bad. If you declare <code class="language-plaintext highlighter-rouge">@Listener(SoftAsserts)</code> for <strong>one</strong> test class, TestNG creates a single instance of <code class="language-plaintext highlighter-rouge">SoftAsserts</code> and uses for <strong>ALL</strong> tests (even parallel).</p> <blockquote> <p>As opposite, JUnit is cool guy. It creates a new instance of every test class and every Rule before running every next test method. Thus it avoids dependencies between tests and random failures because of previous tests.</p> </blockquote> <p>We have fixed this problem. Now <code class="language-plaintext highlighter-rouge">SoftAsserts</code> listener can work in several parallel threads. Even in TestNG.</p> <p>See issues <a href="https://github.com/selenide/selenide/issues/364">#364</a> and <a href="https://github.com/selenide/selenide/issues/303">#303</a>.</p> <h1 id="added-new-methods-to-class-selectors-bycssselector-and-byclassname">Added new methods to class <code class="language-plaintext highlighter-rouge">Selectors</code>: <code class="language-plaintext highlighter-rouge">byCssSelector()</code> and <code class="language-plaintext highlighter-rouge">byClassName()</code></h1> <p>I am still not sure that it’s really needed, but people asked for it many times. No <code class="language-plaintext highlighter-rouge">Selectors</code> has <code class="language-plaintext highlighter-rouge">by*</code> analogues for all selenium <code class="language-plaintext highlighter-rouge">By.*</code> methods.</p> <p>See <a href="https://github.com/selenide/selenide/issues/360">issue #360</a>.</p> <h3 id="fixed-javascript-error-when-running-edge-browser">Fixed JavaScript error when running Edge browser</h3> <p>Now you can run your Selenide tests with the new Microsoft browser Edge. People say it should be quite fast.</p> <p>See <a href="https://github.com/selenide/selenide/issues/339">issue #339</a>.</p> <h3 id="now-method-screenshot-saves-screenshots-in-a-right-place">Now method <code class="language-plaintext highlighter-rouge">$.screenshot()</code> saves screenshots in a right place</h3> <p>Selenide has method for saving screenshot of a single element (not a whole page):</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">String</span> <span class="n">screenshotFile</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#footer"</span><span class="o">).</span><span class="na">screenshot</span><span class="o">();</span> </code></pre></div></div> <p>The problem is that this method saved screenshot to the project root. Now it’s fixed, and saves screenshot to the right place - <code class="language-plaintext highlighter-rouge">build/reports</code> by default.</p> <p>See <a href="https://github.com/selenide/selenide/issues/290">issue #290</a>.</p> <h3 id="added-protection-against-invalid-soft-asserts-usages">Added protection against invalid soft asserts usages</h3> <p>Now Selenide will throw an exception if you enable “Soft asserts” mode, but forget to add <code class="language-plaintext highlighter-rouge">SoftAssert</code> annotation to your test classes.</p> <p>See <a href="https://github.com/selenide/selenide/issues/302">issue #302</a>.</p> <h3 id="we-added-link-to-implementation-to-all-selenideelement-methods-javadoc">We added link to implementation to all <code class="language-plaintext highlighter-rouge">SelenideElement</code> methods’ javadoc</h3> <p>For example, method <a href="https://selenide.org/javadoc/3.8/com/codeborne/selenide/SelenideElement.html#setValue-java.lang.String-">$(“input”).setValue(“hello”)</a> is actually implemented in class <a href="https://selenide.org/javadoc/3.8/com/codeborne/selenide/commands/SetValue.html"><code class="language-plaintext highlighter-rouge">SetValue</code></a></p> <p>See <a href="https://github.com/selenide/selenide/issues/367">issue #367</a>.</p> <h3 id="upgraded-to-htmlunit-223">Upgraded to htmlunit 2.23</h3> <p>See htmlunit <a href="http://htmlunit.sourceforge.net/changes-report.html#a2.23">release notes</a></p> <p><br /></p> <h2 id="news">News</h2> <ul> <li><a href="http://itech.folderit.net/1232/selenide-framework-for-testing-automation/">Article about Selenide in Spanish</a> by Dario Lamy</li> <li><a href="http://asolntsev.github.io/ru/2016/08/05/why-programmer-cannot-be-true-tester/">Why developers must be good testers</a></li> <li>New cool conference in Saint-Petersburg: <a href="http://heisenbug.ru/en/">Heisenbug</a> - looks promising, I am going to speak there</li> <li>New cool article from Uncle Bob: <a href="http://blog.cleancoder.com/uncle-bob/2016/07/27/TheChurn.html">The Churn</a></li> <li><a href="http://asolntsev.github.io/ru/2016/07/08/what-is-hardcode/">What is a true hardcode</a></li> <li><a href="http://asolntsev.github.io/ru/2016/07/09/true-page-object/">True page objects</a></li> </ul> <h3 id="for-dessert">For dessert</h3> <p>And for dessert - a fresh joke about Chuck Norris:</p> <blockquote> <p>Chuck Norris does not use Selenide.<br /> Chuck Norris writes tests in pure Selenium webdriver.<br /> Chuck Norris is immortal - he has enough time for this.</p> </blockquote> <p><br /> <br /></p> <p>Let’s upgrade!</p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2016/08/06/selenide-3.8/ https://selenide.org/2016/08/06/selenide-3.8 2016-08-06T00:00:00+00:00 Released Selenide 3.7 <p>Hi all!</p> <p>We released Selenide 3.7!</p> <h2 id="upgraded-to-selenium-2531">Upgraded to Selenium 2.53.1</h2> <p>It should fix the problem with Firefox 47.</p> <h2 id="added-support-for-marionette-browser">Added support for Marionette browser</h2> <p>To run your tests with Marionette browser, you can set parameter in command line (or build script):</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-Dselenide.browser=marionette </code></pre></div></div> <p>or set browser directly in your 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">browser</span> <span class="o">=</span> <span class="s">"marionette"</span><span class="o">;</span> </code></pre></div></div> <p>see. <a href="https://github.com/selenide/selenide/pull/349">pull request #349</a></p> <p>Thanks to <a href="https://github.com/ridiekel">Geroen Dierckx</a> for this pull request!</p> <h2 id="added-support-for-non-web-drivers">Added support for non-web drivers</h2> <p>There are some “webdrivers” that do not actually drive web-browsers, but</p> <ul> <li>native Windows applications (<a href="https://github.com/2gis/Winium">Winium</a>),</li> <li>Java Swing applications (<a href="https://marathontesting.com/seleniumwebdriver-bindings/">Marathon</a>),</li> <li>and even mobile applications (<a href="http://appium.io/">Appium</a>).</li> </ul> <p>Naturally, these drivers do not support JavaScript. It appeared that Selenide could not work without JavaScript.</p> <p>In Selenide 3.7, we have fixed this problem. Now Selenide should work with non-web drivers.</p> <p>see. <a href="https://github.com/selenide/selenide/issues/345">issue #345</a></p> <h2 id="removed-useless-message-screenshots--if-screenshots-are-disabled">Removed useless message <code class="language-plaintext highlighter-rouge">Screenshots: </code> if screenshots are disabled</h2> <p>see. <a href="https://github.com/selenide/selenide/pull/357">pull request #357</a></p> <p>Thanks to <a href="https://github.com/BorisOsipov">Boris Osipov</a> for this pull request!</p> <p><br /></p> <h2 id="statistics-update">Statistics update</h2> <p>Selenide download statistics for June 2016:</p> <center> <img src="/images/2016/07/selenide.downloads.png" width="800" /> </center> <p>And unique IPs statistics:</p> <center> <img src="/images/2016/07/selenide.unique-ips.png" width="800" /> </center> <p>It’s still growing!</p> <p><br /> <br /></p> <p><a href="http://asolntsev.github.io/">Andrei Solntsev</a></p> <p>selenide.org</p> https://selenide.org/2016/07/08/selenide-3.7/ https://selenide.org/2016/07/08/selenide-3.7 2016-07-08T00:00:00+00:00 We released Selenide 3.6 <p>Good day!</p> <p>In the last day of spring, we released Selenide 3.6.</p> <h2 id="reverted-page-loading-strategy-to-normal">Reverted page loading strategy to <code class="language-plaintext highlighter-rouge">normal</code></h2> <p>In Selenide 3.5 we set default page loading strategy to <code class="language-plaintext highlighter-rouge">none</code>. It made tests faster for some users, but other users complained that it broke their tests, so that they had to rollback to Selenide 3.4.</p> <p>Now the default page loading strategy is again <code class="language-plaintext highlighter-rouge">normal</code> (it’s Selenium default). If you want to speed up your tests, just configure</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">-Dselenide</span>.page-load-strategy<span class="o">=</span>none </code></pre></div></div> <p>or</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">pageLoadStrategy</span> <span class="o">=</span> <span class="s">"none"</span><span class="o">;</span> </code></pre></div></div> <p>See <a href="https://github.com/selenide/selenide/issues/321">issue #321</a></p> <h2 id="now-page-objects-dont-have-to-be-public">Now page objects don’t have to be public</h2> <p>… or have public constructor.</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">GoogleSearchTest</span> <span class="o">{</span> <span class="kd">private</span> <span class="nc">SearchPage</span> <span class="n">search</span><span class="o">;</span> <span class="kd">private</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">SearchPage</span> <span class="o">{</span> <span class="kd">public</span> <span class="nc">ResultsPage</span> <span class="nf">searchFor</span><span class="o">(</span><span class="nc">String</span> <span class="n">keyword</span><span class="o">)</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">"q"</span><span class="o">)).</span><span class="na">val</span><span class="o">(</span><span class="n">keyword</span><span class="o">).</span><span class="na">pressEnter</span><span class="o">();</span> <span class="k">return</span> <span class="nf">page</span><span class="o">(</span><span class="nc">ResultsPage</span><span class="o">.</span><span class="na">class</span><span class="o">);</span> <span class="o">}</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div></div> <p>Make it private. Remove useless constructors. Clean up your code.</p> <p>See <a href="https://github.com/selenide/selenide/issues/335">issue #335</a></p> <h2 id="added-support-for-jbrowser-webdriver">Added support for JBrowser webdriver</h2> <p>JBrowser is a new headless browser (like HtmlUnit and PhantomJS). In theory, it could be faster than usual browsers. In practice, JBrowser seems to be unusable yet: most of Selenide own tests fail with it.</p> <p>But you can try it by yourself: <code class="language-plaintext highlighter-rouge">-Dselenide.browser="jbrowser"</code>.</p> <p>And you will need to add dependency to your project:</p> <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;dependency</span> <span class="na">org=</span><span class="s">"com.machinepublishers"</span> <span class="na">name=</span><span class="s">"jbrowserdriver"</span> <span class="na">rev=</span><span class="s">"[0.13.0, 2.0)"</span> <span class="na">conf=</span><span class="s">"test-default"</span><span class="nt">/&gt;</span> </code></pre></div></div> <p>See <a href="https://github.com/selenide/selenide/issues/329">issue #329</a></p> <p>Thanks to Anil Kumar Reddy Gaddam for this pull request!</p> <h2 id="method-download-now-uses-the-standard-selenide-timeout">Method $().download() now uses the standard selenide timeout</h2> <p>Before this change, method <code class="language-plaintext highlighter-rouge">$.download()</code> could hang sometimes. Now it works no longer that 4 seconds (or whatever timeout you configured).</p> <p>See <a href="https://github.com/selenide/selenide/issues/341">issue #341</a></p> <h2 id="added-support-for-basic-auth-for-all-common-browsers">Added support for Basic Auth for all common browsers</h2> <p>You can find usage examples <a href="https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/BasicAuthTest.java">here</a>:</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="s">"http://httpbin.org/basic-auth/user/passwd"</span><span class="o">,</span> <span class="s">""</span><span class="o">,</span> <span class="s">"user"</span><span class="o">,</span> <span class="s">"passwd"</span><span class="o">);</span> </code></pre></div></div> <p>See <a href="https://github.com/selenide/selenide/issues/320">issue #320</a></p> <p>Thanks to <a href="https://github.com/dimand58">dimand58</a> for this pull request!</p> <h2 id="added-method-screenshotasimage">Added method <code class="language-plaintext highlighter-rouge">$.screenshotAsImage()</code></h2> <p>It allows to get an image of some element. It may be useful for debugging, especially when the page is large, and all elements do not fit on the screen.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">BufferedImage</span> <span class="n">elementScreenshot</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">".logo"</span><span class="o">).</span><span class="na">screenshotAsImage</span><span class="o">();</span> </code></pre></div></div> <p>Thanks to <a href="https://github.com/Akkuzin">Akkuzin</a> for this pull request!</p> <h2 id="fixed-testng-textreport-listener">Fixed TestNG TextReport Listener</h2> <p>now the report will only be generated for classes annotated with <code class="language-plaintext highlighter-rouge">@Report</code>.</p> <p>If I understand correctly, it is a TestNG: if listener is declared in one of test classes, it’s applied to all tests. Like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>@Listeners(TextReport.class) </code></pre></div></div> <p>It may be a problem if you want to generate a report only for some problematic tests.</p> <p>Now we fixed it. The report will not be generated for all test classes, but only those annotated with <code class="language-plaintext highlighter-rouge">@Report</code>.</p> <p>Thanks to <a href="https://github.com/vinogradoff">Alexei Vinogradov</a> for his work on TestNG listeners!</p> <h2 id="upgraded-phantomjsdriver-to-version-130-compatible-with-selenium-java-2530">Upgraded phantomjsdriver to version 1.3.0 (compatible with selenium-java 2.53.0)</h2> <p>Unfortunately, PhantomJS Driver project has been asleep for a while. Its original author Ivan Marino declared that he cannot support the project anymore. :(</p> <p>That’s why we <a href="https://github.com/codeborne/ghostdriver">forked</a> it and released phantomjsdriver 1.3.0, that is compatible with the latest Selenium Webdriver 2.53.0. And now this version is included with Selenide 3.6+.</p> <p><br /></p> <p>That’s all about Selenide 3.6.</p> <p>Download and test with pleasure!</p> <p><br /> <br /></p> <h1 id="other-news">Other news</h1> <ul> <li>It’s not a fantastic, it’s real: <a href="http://seleniumcamp.com/talk/using-selenide-on-c-net/">How to use Selenide in C# .NET</a> / Oleg Volodin</li> <li>One more <a href="http://qiita.com/tatesuke/items/589e30ab9b3dc7037e26">article about Selenide in Japan</a> / tatesuke</li> <li>Tutorial: <a href="https://blog.konstantinpavlov.net/2016/05/12/selenium-tests-with-maven-and-selenide/">Selenium Tests with Maven and Selenide</a> / Konstantin Pavlov</li> </ul> <h2 id="statistics">Statistics</h2> <p>This is Selenide download statistics for May 2016:</p> <center> <img src="/images/2016/06/selenide.downloads.png" width="800" /> </center> <p>The Army of Seleniders is growing!</p> <p><br /> <br /></p> <p>And what’s up with you?</p> <p><br /></p> <p>Andrei Solntsev</p> <p>selenide.org</p> https://selenide.org/2016/06/01/selenide-3.6/ https://selenide.org/2016/06/01/selenide-3.6 2016-06-01T00:00:00+00:00 Released Selenide 3.5 <p>Hi all!</p> <p>We released Selenide 3.5 with flexible collection size checks.</p> <h2 id="we-added-flexible-checks-for-collection-size">We added flexible checks for collection size</h2> <p>Before now, we could only check the exact size of collection:</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">".man.angry"</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">12</span><span class="o">));</span> </code></pre></div></div> <p>Now we can use flexible checks: &lt;, &lt;=, &gt;, &gt;=, &lt;&gt;</p> <p>Simple 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">".man.angry"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">sizeLessThan</span><span class="o">(</span><span class="mi">13</span><span class="o">));</span> <span class="err">$$</span><span class="o">(</span><span class="s">".man.angry"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">sizeLessThanOrEqual</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">".man.angry"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">sizeGreaterThan</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">".man.angry"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">sizeGreaterThanOrEqual</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">".man.angry"</span><span class="o">).</span><span class="na">shouldHave</span><span class="o">(</span><span class="n">sizeNotEqual</span><span class="o">(</span><span class="mi">42</span><span class="o">));</span> </code></pre></div></div> <p>Thanks to <a href="https://github.com/vasilevichra">vasilevichra</a> for this pull request!</p> <p>P.S. Actually I am still not sure that this is a good idea. I think that test must prepare required preconditions before running application. It means that test must always know exactly how many elements should be on the page at every moment. But we implemented it because users kindly asked for it.</p> <h2 id="speed-up-of-page-loading">Speed up of page loading</h2> <p>By default Selenium webdriver waits until all elements of a page (html, script, style, img) are completely loaded. It may be slow, for example, if there are big images on the page. And it’s not really needed, especially in case of Selenide that can wait for any expected conditions.</p> <p>That’s why we used page loading strategy <code class="language-plaintext highlighter-rouge">none</code> in Selenide 3.5. It should make your tests faster.</p> <p>Of course, you still can use any other strategy if you need.</p> <p>Either by system property:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-Dselenide.page-load-strategy=normal </code></pre></div></div> <p>Or directly in code:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Configuration.pageLoadStrategy=eager; </code></pre></div></div> <p>You can find all available strategies <a href="https://w3c.github.io/webdriver/webdriver-spec.html#dfn-page-loading-strategy">here</a>.</p> <h2 id="fixed-method-tostring">Fixed method toString()</h2> <p>Selenide can print detailed information of web elements. When you write <code class="language-plaintext highlighter-rouge">System.out.println($("option#abc"))</code>, you will see a text and all attributes of this element:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;option</span> <span class="na">id=</span><span class="s">"abc"</span> <span class="na">value=</span><span class="s">"livemail.ru"</span> <span class="na">selected:true</span><span class="nt">&gt;</span>@livemail.ru<span class="nt">&lt;/option&gt;</span> </code></pre></div></div> <p>It’s really cool feature, and by the way, Selenium cannot do it.</p> <p>That’s why we had to use dirty JavaScript hacks to print all the attributes.</p> <p>But we found that this method prints only the initial value of attribute <code class="language-plaintext highlighter-rouge">value</code>, even if it has been modified dynamically. We fixed this problem in Selenide 3.5. Now method <code class="language-plaintext highlighter-rouge">toString()</code> always prints out the actual value of <code class="language-plaintext highlighter-rouge">value</code>.</p> <h2 id="upgraded-to-selenium-java-2530">Upgraded to selenium-java 2.53.0</h2> <p>Here is <a href="https://raw.githubusercontent.com/SeleniumHQ/selenium/master/java/CHANGELOG">selenium 2.53.0 changelog</a>.</p> <p><br /> <br /></p> <h1 id="news">News</h1> <ul> <li>The historical moment: <a href="https://en.wikipedia.org/wiki/List_of_GUI_testing_tools">Selenide has been mentioned in Wikipedia</a></li> <li>Yakiv Kramarenko presentation on SeleniumCamp 2016 conference: <a href="http://www.slideshare.net/yashaka/selenide-alternative-in-practice-implementation-lessons-learned-seleniumcamp-2016">Selenide Alternative in Practice</a></li> <li>Selenide receipts: <a href="http://selenide-recipes.blogspot.com.ee/2015/09/mobile-automation-appium-selenide.html">Appium + Selenide</a></li> <li>Post about automation system of the printing company Ardecs Print Activity: <a href="http://www.ardecs.com/blog/27-08-2015/?lang=en">Selenide simply offers not to bother</a></li> <li>Article about Selenide in <a href="http://www.softwaretestingmagazine.com/videos/concise-ui-tests-in-java-with-selenide/?utm_source=feedburner&amp;utm_medium=feed&amp;utm_campaign=Feed%3A+SoftwareTestingMagazine+%28Software+Testing+Magazine%29">Software testing magazine</a></li> <li>Article about Selenide from Fabricio Galdino: <a href="http://mrbool.com/api-selenide-developing-functional-tests-in-java/33952">API Selenide: Developing Functional Tests in Java</a></li> </ul> <p><br /> <br /></p> <h2 id="statistics">Statistics</h2> <p>The following is statistics of Selenide downloads in February 2016:</p> <center> <img src="/images/2016/03/selenide.downloads.png" width="800" /> </center> <p>And number of unique IP:</p> <center> <img src="/images/2016/03/selenide.unique-ips.png" width="800" /> </center> <p>The army of Seleniders is growing!</p> <p>We plan next Selenide release pretty soon. We are going to include proxy server BrowserMobProxy in it, so that Selenide could download files and use other powerful magic.</p> <p>And what’s up with you?</p> <p><br /></p> <p>Andrei Solntsev</p> <p>selenide.org</p> https://selenide.org/2016/03/31/selenide-3.5/ https://selenide.org/2016/03/31/selenide-3.5 2016-03-31T00:00:00+00:00 Released Selenide 3.3 <p>Good evening!</p> <p>We released Selenide 3.3 with support for collections.</p> <h2 id="ajax-support-for-collections">Ajax support for collections</h2> <p>Now collection methods <code class="language-plaintext highlighter-rouge">$$</code> can wait until collection elements get loaded. It can be useful for collections that are loaded asynchronously with Ajax.</p> <p>See. <a href="https://github.com/selenide/selenide/issues/277">issue #277</a></p> <h2 id="added-separate-timeout-for-collections">Added separate timeout for collections</h2> <p>We added two configuration parameters:</p> <ul> <li><code class="language-plaintext highlighter-rouge">collectionsTimeout</code> (default value 6 seconds)</li> <li><code class="language-plaintext highlighter-rouge">collectionsPollingInterval</code> (default value 0.2 seconds)</li> </ul> <p>Typically collections are loaded longer than single elements (they contain more than one element). That’s why they need longer timeout.</p> <h2 id="upgraded-to-selenium-java-2510">Upgraded to selenium-java 2.51.0</h2> <p>See <a href="https://raw.githubusercontent.com/SeleniumHQ/selenium/master/java/CHANGELOG">selenium 2.51.0 changelog</a>.</p> <p><br /> <br /></p> <h1 id="news">News</h1> <ul> <li>Java Advent calendar: <a href="http://www.javaadvent.com/2015/12/effective-ui-tests-with-selenide.html">Effective UI tests with Selenide</a></li> <li>Post about Selenide <a href="http://hanmomhanda.github.io/2016/01/27/Selenide-%EA%BF%80%ED%8C%81/">on KOREAN</a>.</li> <li>Post about Selenide <a href="http://www.devmedia.com.br/api-selenide-desenvolvimento-de-testes-funcionais-em-java/33680">on Portugal</a>.</li> <li><a href="https://gist.github.com/mkpythonanywhereblog/947633ba1bf0bc239639">Selenide cheat sheet</a></li> <li><a href="http://selenide-recipes.blogspot.kr/2015/08/6-waits.html">Selenide receipts</a></li> </ul> <h1 id="lets-communicate">Let’s communicate!</h1> <p>Now we have new possibilities to discuss new features and old problems of Selenide. You are welcome!</p> <ul> <li><a href="https://selenide.slack.com/messages/general/">Slack chat</a></li> <li><a href="https://gitter.im/codeborne/selenide">Gitter chat</a></li> </ul> <p><br /> <br /></p> <p>And what’s up with you?</p> <p><br /></p> <p>Andrei Solntsev</p> <p>selenide.org</p> https://selenide.org/2016/02/11/selenide-3.3/ https://selenide.org/2016/02/11/selenide-3.3 2016-02-11T00:00:00+00:00 Released Selenide 3.2 <p>Good morning!</p> <p>We released Selenide 3.2</p> <h2 id="now-selenide-logs-browser-version">Now Selenide logs browser version</h2> <p>We added INFO log containing version of browser, Selenium and Selenide:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>00:32:45 INFO BrowserName=chrome Version=48.0.2564.109 Platform=MAC 00:32:45 INFO Selenide v. 3.2 00:32:45 INFO Selenium WebDriver v. 2.51.0 build time: 2016-02-05 11:20:57 </code></pre></div></div> <h2 id="better-report">Better report</h2> <p>We renamed FAILED-&gt;FAIL, PASSED-&gt;PASS in selenide report. So they don’t mess with <code class="language-plaintext highlighter-rouge">PASSED</code> and <code class="language-plaintext highlighter-rouge">FAILED</code> that are typically written by Maven and other tools. Now it’s a little bit easier to analyze Selenide output in Jenkins.</p> <h2 id="added-method-for-selecting-option-by-index">Added method for selecting option by index</h2> <p>Before Selenide 3.2 you could select an option by text or value:</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#email"</span><span class="o">).</span><span class="na">selectOption</span><span class="o">(</span><span class="s">"@gmail.com"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"select#email"</span><span class="o">).</span><span class="na">selectOptionByValue</span><span class="o">(</span><span class="s">"98347643"</span><span class="o">);</span> </code></pre></div></div> <p>Now you can also <a href="https://github.com/selenide/selenide/issues/275">select option by index</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">"select#email"</span><span class="o">).</span><span class="na">selectOption</span><span class="o">(</span><span class="mi">4</span><span class="o">);</span> </code></pre></div></div> <h2 id="added-setting-selenidebrowser-size">Added setting <code class="language-plaintext highlighter-rouge">selenide.browser-size</code></h2> <p>Now you can set <a href="https://github.com/selenide/selenide/issues/272">browser size</a> before running tests:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>java <span class="nt">-Dselenide</span>.browser-size<span class="o">=</span>1024x768 </code></pre></div></div> <p>or directly in code:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Before</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setUp</span><span class="o">()</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="s">"chrome"</span><span class="o">;</span> <span class="nc">Configuration</span><span class="o">.</span><span class="na">browserSize</span> <span class="o">=</span> <span class="s">"1024x768"</span><span class="o">;</span> <span class="o">}</span> </code></pre></div></div> <p>It’s probably a good idea to declare a (minimal) expected browser size supported by the application in test. So your tests will verify that the application works on that small displays.</p> <h2 id="upgraded-to-selenium-java-2500">Upgraded to selenium-java 2.50.0</h2> <p>See <a href="https://raw.githubusercontent.com/SeleniumHQ/selenium/master/java/CHANGELOG">selenium 2.50.0 changelog</a>.</p> <p><br /> <br /></p> <p>See you later! Selenide 3.3 is coming soon!</p> <p><br /></p> <p>Andrei Solntsev</p> <p>selenide.org</p> https://selenide.org/2016/01/29/selenide-3.2/ https://selenide.org/2016/01/29/selenide-3.2 2016-01-29T00:00:00+00:00 Released Selenide 3.1 <p>Good evening!</p> <p>Good new year news: we released Selenide 3.1.</p> <h2 id="updated-documentation">Updated documentation</h2> <p>We fixed and updated <a href="/documentation.html">documentation</a> on site.</p> <p>Thanks to <a href="https://github.com/vinogradoff">Aleksei Vinogradov</a> and Erik Khalimov for hard work!</p> <h2 id="method-download-does-not-allow-invisible-links">Method <code class="language-plaintext highlighter-rouge">$().download()</code> does not allow invisible links</h2> <p>Before Selenide 3.1, method <code class="language-plaintext highlighter-rouge">$().download()</code> allowed to download files from invisible links. We fixed this <a href="https://github.com/selenide/selenide/issues/263">bug</a>. Thanks to <a href="https://github.com/dimand58">@dimand58</a> for this <a href="https://github.com/selenide/selenide/pull/264">pull request</a>.</p> <h2 id="methods-switchto-now-can-wait-if-needed">Methods <code class="language-plaintext highlighter-rouge">switchTo(...)</code> now can wait if needed</h2> <p>Methods <code class="language-plaintext highlighter-rouge">switchTo(alert())</code>, <code class="language-plaintext highlighter-rouge">switchTo(frame())</code>, <code class="language-plaintext highlighter-rouge">switchTo(window())</code> got smarter. Now they can wait a little bit, if <a href="https://github.com/selenide/selenide/issues/206">alert</a>, <a href="https://github.com/selenide/selenide/issues/206">frame</a> or <a href="https://github.com/selenide/selenide/issues/271">window</a> is not loaded yet. As usually, default timeout is 4 seconds.</p> <h2 id="added-methods-byname-byxpath-bylinktext-bypartiallinktext-byid">Added methods <code class="language-plaintext highlighter-rouge">byName</code>, <code class="language-plaintext highlighter-rouge">byXpath</code>, <code class="language-plaintext highlighter-rouge">byLinkText</code>, <code class="language-plaintext highlighter-rouge">byPartialLinkText</code>, <code class="language-plaintext highlighter-rouge">byId</code></h2> <p>These are new static methods in class <code class="language-plaintext highlighter-rouge">Selectors</code> (where methods <code class="language-plaintext highlighter-rouge">byText</code> and <code class="language-plaintext highlighter-rouge">withText</code> were). Actually they are just aliases for selenium built-in <code class="language-plaintext highlighter-rouge">By.*</code> methods. I am not sure they are really useful, but some folks like the idea of not using any Selenium classes in their tests. Also it was needed for folks who use Selenide in their .NET tests. Imagine, people!</p> <h2 id="conditionshouldhaveexacttextcasesensitive-checks-the-entire-string">Condition<code class="language-plaintext highlighter-rouge">$.shouldHave(exactTextCaseSensitive("..."))</code> checks the entire string</h2> <p>Before Selenide 3.1 it checks only a substring. We fixed this bug.</p> <h2 id="methods-webelement-selector-and-webelement-selector-marked-as-deprecated">Methods <code class="language-plaintext highlighter-rouge">$(WebElement, selector)</code> and <code class="language-plaintext highlighter-rouge">$$(WebElement, selector)</code> marked as deprecated</h2> <p>It’s recommended to use method <code class="language-plaintext highlighter-rouge">find</code> instead:</p> <ul> <li><code class="language-plaintext highlighter-rouge">$(WebElement).find(selector)</code></li> <li><code class="language-plaintext highlighter-rouge">$$(WebElement).find(selector)</code></li> </ul> <h2 id="added-method-getvalue">Added method <code class="language-plaintext highlighter-rouge">$.getValue()</code></h2> <p>Actually this is just an alias for <code class="language-plaintext highlighter-rouge">$.val()</code>.</p> <h2 id="selenide-includes-phantomjsdriver-121-out-of-the-box">Selenide includes phantomjsdriver 1.2.1 out of the box</h2> <p>Now you don’t need to include additional dependencies to use PhantomJS in your tests.</p> <h2 id="upgraded-to-selenium-java-2490">Upgraded to selenium-java 2.49.0</h2> <p>See <a href="https://raw.githubusercontent.com/SeleniumHQ/selenium/master/java/CHANGELOG">selenium 2.49.0 changelog</a>.</p> <p><br /> <br /></p> <p>See you! Selenide 3.2 and 3.3 is coming soon!</p> <p><br /></p> <p>Andrei Solntsev</p> <p>selenide.org</p> https://selenide.org/2016/01/17/selenide-3.1/ https://selenide.org/2016/01/17/selenide-3.1 2016-01-17T00:00:00+00:00 Released Selenide 3.0 <p>Hello!</p> <p>We released Selenide 3.0. Finally!</p> <p>NB! Selenide 3.0 is a major upgrade, meaning that something can become broken.</p> <p>Don’t be afraid: if you used only public API and didn’t used @Deprecated methods, then nothing changes for you. But if you did, read carefully.</p> <h2 id="historical-notes">Historical notes</h2> <p>The first version Selenide 1.0 was created in year 2011. We silently tested and tuned it for more than a year.</p> <p>In March 2013 we went to SeleniumCamp conference in Kiev and released Selenide 2.0 there. In 2.0 we cleaned up all the legacy and left only the new API. Then was the first “public” version of Selenide 2.0 born. At that moment, <code class="language-plaintext highlighter-rouge">SelenideElement</code> has only a dozen of methods and was called <code class="language-plaintext highlighter-rouge">ShouldableWebElement</code>. :)</p> <p>Since that we released 25 versions Selenide, it got a lot of new functions, and its own legacy @Deprecated methods. We needed changes.</p> <p>That’s why we finally released Selenide 3.0</p> <h2 id="new-functions-in-selenide-30">New functions in Selenide 3.0</h2> <p>There is only one new function - method <code class="language-plaintext highlighter-rouge">Selenide.updateHash()</code>. It’s useful for testing rich ajax applications that react to “#” changes in URL. Method <code class="language-plaintext highlighter-rouge">updateHash()</code> changes “#bla-bla” part of current URL without reloading the page.</p> <p>Look <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/UpdateHashTest.java">here</a> for usage example.</p> <blockquote> <p>Thanks to @fabienbancharel for pull request #254</p> </blockquote> <h2 id="upgraded-dependencies">Upgraded dependencies</h2> <ul> <li>upgraded to Sizzle 2.2.1</li> <li>upgraded to Guava 19.0</li> <li>upgraded to TestNG 6.9.10</li> </ul> <p>It only affects you if you use some of these libraries.</p> <h2 id="big-refactoring">Big refactoring</h2> <ul> <li>We refactored class <code class="language-plaintext highlighter-rouge">AbstractSelenideElement</code>. Now, instead of one huge class, we have a lot of small classes (in package <code class="language-plaintext highlighter-rouge">com.codeborne.com.commands</code>). Everyone of them has its own responsibility.</li> <li>You can easily override any of <code class="language-plaintext highlighter-rouge">SelenideElement</code> methods.</li> <li>You can even add your own methods to standard Selenide and Selenium methods.</li> </ul> <p>We will describe these great options in details in a separate post, but you can look to examples in <a href="https://github.com/selenide/selenide/tree/master/statics/src/test/java/integration/customcommands">Selenide tests</a>.</p> <blockquote> <p>Thanks to Iakiv Kramarenko for his ideas and night discussions.</p> </blockquote> <h2 id="big-cleanup">Big cleanup</h2> <p>Like we announce earlier, we cleaned up all the old stuff.</p> <ul> <li>Remove deprecated conditions: <ul> <li><code class="language-plaintext highlighter-rouge">notPresent</code> -&gt; Use method <code class="language-plaintext highlighter-rouge">$.shouldNot(exist)</code> or <code class="language-plaintext highlighter-rouge">$.shouldNotBe(present)</code>.</li> <li><code class="language-plaintext highlighter-rouge">hasOptions</code> -&gt; Not needed anymore. Use methods <code class="language-plaintext highlighter-rouge">$.selectOption()</code> or <code class="language-plaintext highlighter-rouge">$.selectOptionByValue()</code>.</li> <li><code class="language-plaintext highlighter-rouge">options</code> -&gt; Not needed anymore. Use methods <code class="language-plaintext highlighter-rouge">$.selectOption()</code> or <code class="language-plaintext highlighter-rouge">$.selectOptionByValue()</code>.</li> <li><code class="language-plaintext highlighter-rouge">hasNotClass</code> -&gt; Use method <code class="language-plaintext highlighter-rouge">$.shouldNotHave(cssClass("abc"))</code></li> </ul> </li> <li>Remove deprecated class JQuery</li> <li>Remove deprecated class PrettyReportCreator (use class <code class="language-plaintext highlighter-rouge">TextReport</code> for JUnit or TestNG)</li> <li>Remove deprecated methods <ul> <li><code class="language-plaintext highlighter-rouge">Selenide.switchToWindow(title)</code> -&gt; use method <code class="language-plaintext highlighter-rouge">switchTo().window(title)</code></li> <li><code class="language-plaintext highlighter-rouge">Selenide.switchToWindow(index)</code> -&gt; use method <code class="language-plaintext highlighter-rouge">switchTo().window(index)</code></li> </ul> </li> <li>Remove deprecated methods <ul> <li><code class="language-plaintext highlighter-rouge">WebDriverRunner.ie()</code> -&gt; use method <code class="language-plaintext highlighter-rouge">WebDriverRunner.isIE()</code></li> <li><code class="language-plaintext highlighter-rouge">WebDriverRunner.htmlUnit()</code> -&gt; use method <code class="language-plaintext highlighter-rouge">WebDriverRunner.isHtmlUnit()</code></li> <li><code class="language-plaintext highlighter-rouge">WebDriverRunner.phantomjs()</code> -&gt; use method <code class="language-plaintext highlighter-rouge">WebDriverRunner.isPhantomjs()</code></li> <li><code class="language-plaintext highlighter-rouge">WebDriverRunner.takeScreenShot()</code> -&gt; use method <code class="language-plaintext highlighter-rouge">Screenshots.takeScreenShot()</code></li> </ul> </li> <li>Remove deprecated methods <ul> <li><code class="language-plaintext highlighter-rouge">$.should*(String message, Condition condition)</code> -&gt; use method <code class="language-plaintext highlighter-rouge">$.should*(condition.because(message))</code></li> </ul> </li> <li>Remove class com.codeborne.selenide.impl.Quotes because it was migrated to Selenium Webdriver (org.openqa.selenium.support.ui.Quotes)</li> </ul> <p>Feel free to give feedback if you get something broken.</p> <p><br /> <br /></p> <h1 id="news">News</h1> <ul> <li>Selenide got to <a href="http://www.coderbucket.com/best-tools-sites-java/">Best tools and sites for Java in 2015</a></li> <li>Article about Selenide in Java Advent Calendar 2015 <a href="http://www.javaadvent.com/2015/12/effective-ui-tests-with-selenide.html">Effective UI tests with Selenide</a></li> <li>Article about Selenide in Japan <a href="http://qiita.com/kazuki-ma/items/d6432fc41c82538a61bd">Selenide Java Library:簡単なことは簡単に,Web UI テスト自動化の敷居を下げ,生産性をあげる魔法の Wrapper</a></li> </ul> <p><br /></p> <p>Happy new year!</p> <p>I wish you fast and effective tests.</p> <p><br /></p> <p>Andrei Solntsev</p> <p>selenide.org</p> https://selenide.org/2015/11/30/selenide-3.0/ https://selenide.org/2015/11/30/selenide-3.0 2015-11-30T00:00:00+00:00 Changes in Selenide 2.25 <p>Good evening!</p> <p>Today we released Selenide 2.25. It’s the last Selenide version in 2.* line. A big refactoring, clean-up of deprecated stuff and Selenide 3.0 follows soon.</p> <p>Please review your tests and be sure you don’t use any @Deprecated methods. We are going to remove them in Selenide 3.0.</p> <p>But now - Selenide 2.25 highlights:</p> <h2 id="we-added-selenide-profiler-for-testng">We added “Selenide profiler” for TestNG</h2> <p>You probably know that Selenide suggests a profiler for your tests named <a href="https://selenide.org/2015/05/05/selenide-2.16-and-2.17/">PrettyReportCreator</a>. It was only available for JUnit until now. Now we created the same profiler for TestNG.</p> <p>By the way, we renamed it to <code class="language-plaintext highlighter-rouge">TextReport</code>.</p> <p>To use profiler with JUnit:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nd">@Rule</span> <span class="kd">public</span> <span class="nc">TestRule</span> <span class="n">report</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">TextReport</span><span class="o">();</span> </code></pre></div></div> <p>To use profiler with TestNG:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nd">@Listeners</span><span class="o">(</span><span class="nc">TextReport</span><span class="o">.</span><span class="na">class</span><span class="o">)</span> <span class="kd">public</span> <span class="kd">class</span> <span class="nc">GoogleTestNGTest</span> <span class="o">{</span> <span class="o">...</span> <span class="o">}</span> </code></pre></div></div> <h2 id="we-added-methods-first-and-last">We added methods <code class="language-plaintext highlighter-rouge">$$.first()</code> and <code class="language-plaintext highlighter-rouge">$$.last()</code></h2> <p>Now it’s easy to get the first and the last elements of a collection:</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">"#employees .fired"</span><span class="o">).</span><span class="na">first</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">"Steve Jobs"</span><span class="o">));</span> <span class="err">$$</span><span class="o">(</span><span class="s">"#employees .fired"</span><span class="o">).</span><span class="na">last</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">"Richard Williamson"</span><span class="o">));</span> </code></pre></div></div> <h2 id="we-added-method-screenshotsgetlastscreenshot">We added method <code class="language-plaintext highlighter-rouge">Screenshots.getLastScreenshot()</code></h2> <p>It returns <em>the last</em> screenshot taken by Selenide. It’s can be useful for those who wants to integrate Selenide with reporting frameworks like Allure.</p> <p>By the way, we renamed method <code class="language-plaintext highlighter-rouge">getScreenShotAsFile()</code> to <code class="language-plaintext highlighter-rouge">takeScreenShotAsFile()</code>, because the former name was wrong: this method does take a screenshot, not only returns a screenshot.</p> <h2 id="we-added-methods-selenideconfirm-and-selenidedismiss">We added methods Selenide.confirm() and Selenide.dismiss()</h2> <p>For handling modal dialogs, Selenide had methods <code class="language-plaintext highlighter-rouge">confirm(String)</code> and <code class="language-plaintext highlighter-rouge">dismiss(String)</code> with parameter - expected dialog text.</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="s">"Are you sure you want to remove file?"</span><span class="o">);</span> <span class="n">dismiss</span><span class="o">(</span><span class="s">"Are you sure you want to remove file?"</span><span class="o">);</span> </code></pre></div></div> <p>These methods click “ok” or “cancel” in a modal dialog “confirm” and check the dialog’s text.</p> <p>But sometimes you don’t need to check the text. That’s why we added parameterless methods <code class="language-plaintext highlighter-rouge">confirm()</code> and <code class="language-plaintext highlighter-rouge">dismiss()</code>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">String</span> <span class="n">text</span> <span class="o">=</span> <span class="n">confirm</span><span class="o">();</span> <span class="nc">String</span> <span class="n">text</span> <span class="o">=</span> <span class="n">dismiss</span><span class="o">();</span> </code></pre></div></div> <p>these methods do not check, but return dialog text.</p> <h2 id="we-added-option--dselenidereopenbrowseronfail">We added option <code class="language-plaintext highlighter-rouge">-Dselenide.reopenBrowserOnFail</code></h2> <p>By default Selenide tries to re-open browser if it died. It seems to be a good idea: one test fails, but the following tests will continue running.</p> <p>But sometimes you want to avoid re-opening the browser and let all other tests fail.</p> <p>In this case just use the new option: <code class="language-plaintext highlighter-rouge">-Dselenide.reopenBrowserOnFail=false</code></p> <h2 id="upgraded-to-htmlunit-219">Upgraded to htmlunit 2.19</h2> <p>Some folks think that HtmlUnit is died, but we still like it. At least tests of Selenide itself run stably on HtmlUnit.</p> <h2 id="changed-selenide-license-mit">Changed Selenide license MIT</h2> <p>We wrote about license <a href="https://selenide.org/2015/11/16/selenide-changes-license-to-mit/">in a separate post</a>, but shortly said - MIT license is the most permissive. We hope that some bureaucratic companies who are afraid of “GPL” characters can now start using Selenide.</p> <p><br /></p> <h1 id="news">News</h1> <ul> <li><a href="/2015/11/13/selenide-on-devoxx/">Selenide presentation</a> on Devoxx 2015 - the biggest Java conference in Europe</li> </ul> <p><br /></p> <p>And what’s up with you?</p> <p><br /></p> <p>Andrei Solntsev</p> <p>selenide.org</p> https://selenide.org/2015/11/30/selenide-2.25/ https://selenide.org/2015/11/30/selenide-2.25 2015-11-30T00:00:00+00:00 Selenide changes license to MIT <p>Good evening!</p> <p>We decided to change Selenide license from LGPL to MIT.</p> <p>Shortly said, it means that you can do with Selenide <em>whatever</em>.</p> <p>MIT is <strong>the most permissive license</strong>.</p> <p><a href="http://choosealicense.com/">Here you can find</a> illustration for differences between most common open-source licenses MIT, Apache and GPL.</p> <h3 id="why-not-lgpl">Why not LGPL?</h3> <p>Actually we like LGPL. LGPL means that you must publish your code as open-source <strong>only if</strong> you include Selenide code into your product. But you use Selenide in tests, so you don’t include Selenide into code that is delivered to your customers. That’s why you don’t need to publish your source code.</p> <h3 id="why-we-changed-the-license">Why we changed the license?</h3> <p>It seems that many companies are just afraid of GPL. They just don’t want to have any business with GPL, without diving into details. That’s why we decided to switch Selenide license to the most permissive - MIT license.</p> <p>If you have any friends that didn’t use Selenide because of license - now you have good news for them! :)</p> <p>Andrei Solntsev</p> <p>selenide.org</p> https://selenide.org/2015/11/16/selenide-changes-license-to-mit/ https://selenide.org/2015/11/16/selenide-changes-license-to-mit 2015-11-16T00:00:00+00:00 Selenide presentation on Devoxx 2015 <p>Now in Europe!</p> <p>I have presented Selenide on Devoxx - the biggest Java conference in Europe.</p> <p>Here is video of my talk:</p> <div class="wrapper-content center"> <iframe width="840" height="473" src="https://www.youtube.com/embed/BjEW08vDUfI" frameborder="0" allowfullscreen=""></iframe> </div> <p>And slides:</p> <div class="wrapper-content center"> <iframe src="https://docs.google.com/presentation/d/1qA_0wC2pV9IQZu3DoLwm8yGQ_9DlM1WdNzUYgAWFGiQ/embed?start=false&amp;loop=false&amp;delayms=3000" frameborder="0" width="960" height="569" allowfullscreen="allowfullscreen" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe> </div> <p><br /></p> <p><a href="https://www.youtube.com/channel/UCCBVCTuk6uJrN3iFV_3vurg">Here</a> you can find other Devoxx 2015 videos.</p> <p>Andrei Solntsev</p> <p>selenide.org</p> https://selenide.org/2015/11/13/selenide-on-devoxx/ https://selenide.org/2015/11/13/selenide-on-devoxx 2015-11-13T00:00:00+00:00 Changes in Selenide 2.24 <p>Good morning! We released Selenide 2.24. It’s a minor release.</p> <h2 id="upgraded-to-selenium-java-2482">Upgraded to selenium-java 2.48.2</h2> <p><a href="https://raw.githubusercontent.com/SeleniumHQ/selenium/master/java/CHANGELOG">changelog of selenium 2.48.2</a>.</p> <h2 id="add-method-pressescape">Add method <code class="language-plaintext highlighter-rouge">$.pressEscape()</code></h2> <p>In addition to 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">"input"</span><span class="o">).</span><span class="na">pressEnter</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">pressTab</span><span class="o">();</span> </code></pre></div></div> <p>we have now new 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">"input"</span><span class="o">).</span><span class="na">pressEscape</span><span class="o">();</span> </code></pre></div></div> <h2 id="fixed-soft-asserts-for-testng">Fixed soft asserts for TestNG</h2> <p>As you probably know Selenide has <a href="http://ru.selenide.org/2015/05/05/selenide-2.16-and-2.17/">soft asserts</a> functionality. Some time ago it was broken if you run tests in TestNG. Now we fixed it.</p> <h2 id="logic-of-webdriver-creation-extracted-to-a-separate-class-webdriverfactory">Logic of webdriver creation extracted to a separate class WebDriverFactory</h2> <p>Before this release, class <code class="language-plaintext highlighter-rouge">WebDriverRunner</code> created browsers. But it grew to be too large: it also detects hanging browsers, closes and reopens browsers etc. That’s why we extracted logic of <strong>creating</strong> webdrivers to a separate class.</p> <h1 id="news">News</h1> <ul> <li>Conference Devoxx.be<br /> I will <a href="http://cfp.devoxx.be/2015/talk/QBD-3461/Selenide:_concise_UI_Tests_in_Java._From_developers_for_developers.">present Selenide</a> at the largest European Java conference Devoxx in Antwerp<br /> That’s great!</li> </ul> <p><br /></p> <p>And what’s up with you?</p> <p><br /></p> <p>Andrei Solntsev</p> <p>selenide.org</p> https://selenide.org/2015/11/08/selenide-2.24/ https://selenide.org/2015/11/08/selenide-2.24 2015-11-08T00:00:00+00:00 Introduction to Selenide on SeleniumConf 2015 <p>Finally!</p> <p>I have got a change to introduce Selenide on SeleniumConf conference that took place in Portland this year.</p> <p>Here is video of my talk:</p> <div class="wrapper-content center"> <iframe width="840" height="473" src="https://www.youtube.com/embed/fR8CyLcxBZ0" frameborder="0" allowfullscreen=""></iframe> </div> <p>And slides:</p> <div class="wrapper-content center"> <iframe src="https://docs.google.com/presentation/d/1ZksjuL2vPN_pkhMuon0HH4gm7KNmjU50pByRRGzgVko/embed?start=false&amp;loop=false&amp;delayms=3000" frameborder="0" width="960" height="569" allow="fullscreen" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe> </div> <p><br /></p> <p><a href="http://confengine.com/selenium-conf-2015/schedule">Here</a> you can find other SeleniumConf videos.</p> <p>Andrei Solntsev</p> <p>selenide.org</p> https://selenide.org/2015/09/23/selenide-on-seleniumconf/ https://selenide.org/2015/09/23/selenide-on-seleniumconf 2015-09-23T00:00:00+00:00 Changes in Selenide 2.23 <p>Hi all!</p> <p>In september we released Selenide 2.23. Let’s take a look on news.</p> <h2 id="new-method-selectradio">New method <code class="language-plaintext highlighter-rouge">$.selectRadio()</code></h2> <p>In order to select radio button, Selenide had a method</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">selectRadio</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">"gender"</span><span class="o">),</span> <span class="s">"male"</span><span class="o">);</span> </code></pre></div></div> <p>Now we have new method that is more consistent with other Selenide 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="nc">By</span><span class="o">.</span><span class="na">name</span><span class="o">(</span><span class="s">"gender"</span><span class="o">)).</span><span class="na">selectRadio</span><span class="o">(</span><span class="s">"male"</span><span class="o">);</span> </code></pre></div></div> <p>As other Selenide methods, it can wait if the radio button is not available yet.</p> <h2 id="method-setvalue-can-now-handle-radio-buttons">Method <code class="language-plaintext highlighter-rouge">$.setValue()</code> can now handle radio buttons</h2> <p>We try to make Selenide as universal as possible, so that you would not need to think about low-level technical details of web elements. For instance, method <code class="language-plaintext highlighter-rouge">$.setValue()</code> detects what type of web element you are operating with: <code class="language-plaintext highlighter-rouge">input</code>, <code class="language-plaintext highlighter-rouge">select</code> or <code class="language-plaintext highlighter-rouge">textarea</code> - and behaves correspondingly.</p> <p>Now it also supports radio buttons.</p> <p>Method <code class="language-plaintext highlighter-rouge">$.setValue()</code> can now select radio buttons too:</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">"gender"</span><span class="o">)).</span><span class="na">setValue</span><span class="o">(</span><span class="s">"male"</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">"gender"</span><span class="o">)).</span><span class="na">val</span><span class="o">(</span><span class="s">"male"</span><span class="o">);</span> </code></pre></div></div> <h2 id="you-cannot-set-value-to-readonly-field">You cannot set value to readonly field</h2> <p>Now method <code class="language-plaintext highlighter-rouge">$.setValue()</code> will throw an exception if you try to set value into <code class="language-plaintext highlighter-rouge">readonly</code> field.</p> <p>Be aware, it probably can break your tests.</p> <h2 id="method-setvalue-takes-attribute-maxlength-into-account">Method <code class="language-plaintext highlighter-rouge">$.setValue()</code> takes attribute <code class="language-plaintext highlighter-rouge">maxlength</code> into account</h2> <p>If you try to enter too long text to input field having attribute <code class="language-plaintext highlighter-rouge">maxlength</code>, Selenide will cut the text.</p> <p>Be aware, it also can break your tests.</p> <h2 id="fixed-issue-with-unclosed-firefox-instances">Fixed issue with unclosed FireFox instances</h2> <p>Some users reported problems with Firefox browsers that left unclosed after running Selenide tests.</p> <p>Unfortunately we could not reproduce the problem, so that we just had to roll back the old good mechanism of running browsers. We will continue work on new mechanism with timeouts check.</p> <p><br /> <br /></p> <h1 id="news">News</h1> <p>Let me share some great news with you.</p> <ul> <li>Conference SeleniumConf 2015<br /><br /> Finally! <br />Selenide was presented at the annual SeleniumConf conference that was held this time in Portland, USA.<br /> Here is <a href="https://www.youtube.com/watch?v=fR8CyLcxBZ0">video</a> and <a href="https://t.co/Ih8FQ7VJMj">slides</a> of my talk.<br /><br /> By the way, other SeleniumConf 2015 videos are available <a href="https://www.youtube.com/results?filters=month&amp;lclk=month&amp;search_query=seconf2015">here</a>. <br /><br /></li> <li>Historical moment: a book about Selenide has been published! Actually title of book is <a href="http://www.amazon.com/Test-Driven-Java-Development-Viktor-Farcic/dp/1783987421">Test-Driven Java Development</a>, but it contains code samples in Selenide with JBehave and Cucumber. <br /> It’s just unbelievable, but this is true!<br /></li> </ul> <center> <img src="/images/2015/09/test-driver-java-development.2015.jpg" /> </center> <p><br /><br /></p> <ul> <li>Selenide was also presented at Socrates conference at Germany: <a href="http://www.tuicool.com/articles/VbUjYr">Ext JS 5 Tests with Selenide</a></li> </ul> <h2 id="statistics">Statistics</h2> <p>The following is statistics of Selenide downloads in August:</p> <center> <img src="/images/2015/09/selenide_downloads.png" width="800" /> </center> <p>There will come much more in September!</p> <p><br /></p> <p>And what’s up with you?</p> <p><br /></p> <p>Andrei Solntsev</p> <p>selenide.org</p> https://selenide.org/2015/09/15/selenide-2.23/ https://selenide.org/2015/09/15/selenide-2.23 2015-09-15T00:00:00+00:00 Changes in Selenide 2.21 and 2.22 <p>Good saturday!</p> <p>Recently we released Selenide 2.21 and 2.22. They contain few but important changes.</p> <h2 id="upgrade-to-java-7">Upgrade to Java 7</h2> <p>Starting from version 2.21, Selenide only works on Java 7 and higher.</p> <p>If you used Java 6, it’s time to upgrade.</p> <h2 id="upgrade-to-selenium-2471">Upgrade to Selenium 2.47.1</h2> <ul> <li>It requires Java 7.</li> <li>It supports native events only for FireFox 31. For later FireFox versions only synthetic events are supported.</li> <li>It adds experimental support for the new browser “Microsoft Edge”.</li> </ul> <p><a href="https://github.com/SeleniumHQ/selenium/blob/master/dotnet/CHANGELOG">All changes in Selenium 2.47.1</a></p> <h2 id="fixed-problem-with-unclosed-browsers">Fixed problem with unclosed browsers</h2> <p>In Selenide 2.20 we reworked mechanism of closing browser. But it caused a defect: sometimes browser left open. Now this problem is fixed.</p> <p><br /> <br /></p> <h1 id="thank-you-for-your-help">Thank you for your help!</h1> <p>Thanks for all who voted for my proposal. It was accepted to the <a href="http://year-2015.seleniumconf.org/">SeleniumConf 2015</a> conference. I am going 8.09 to Portland to present Selenide at the world’s biggest Selenium conference.</p> <p><br /></p> <p>And what’s up to you?</p> <p><br /></p> <p>Andrei Solntsev</p> <p>selenide.org</p> https://selenide.org/2015/08/29/selenide-2.22/ https://selenide.org/2015/08/29/selenide-2.22 2015-08-29T00:00:00+00:00 Changes in Selenide 2.20 <p>Hi all!</p> <p>We have released Selenide 2.20. Let me tell you what’s new there.</p> <h2 id="protection-against-webdriver-hanging">Protection against webdriver hanging</h2> <p>Sometimes we experience problems with webdriver: it hangs when trying to open or close browser. This thread just remains endlessly in the same state: “Forwarding newSession on session null to remote”. I guess it’s a bug in webdriver.</p> <p>We added protection against this problem in Selenide 2.20.</p> <p>Now Selenide runs opening/closing browser in a separate thread and limits its time. By default opening browser cannot take more than 15 seconds, and closing browser cannot take more than 5 seconds. In case of failure, Selenide re-tries (up to 3 times) and only then throws an exception.</p> <p>Thank you <a href="https://github.com/admizh">@admizh</a> for this suggestion!</p> <p>See <a href="https://github.com/selenide/selenide/issues/199">Issue 199</a> and <a href="https://github.com/selenide/selenide/issues/204">Issue 204</a></p> <h2 id="selenide-now-uses-javautillogging-for-logging">Selenide now uses java.util.logging for logging</h2> <p>Up to now, Selenide used <code class="language-plaintext highlighter-rouge">System.out</code> and <code class="language-plaintext highlighter-rouge">System.err</code> for printing its messages.</p> <p>Actually I think that this is good enough for testing. It’s simple and reliable.</p> <p>But people often use different libraries/frameworks, and want to use common logging mechanism across all tests. That’s why we migrated Selenide to use “standard” mechanism <code class="language-plaintext highlighter-rouge">java.util.logging</code> (JUL).</p> <blockquote> <p>To be honest, I don’t like jul. I think that log4j or slf4j is much better. But Selenium already uses JUL, so it seemed reasonable to use JUL also in Selenide instead of adding new dependencies.</p> </blockquote> <p>Good news is that you don’t need to do anything to use the new logging. It works automatically. It prints logs to standard system output (aka console) by default. But it’s not beautiful:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Jul</span> <span class="mi">25</span><span class="o">,</span> <span class="mi">2015</span> <span class="mi">10</span><span class="o">:</span><span class="mi">48</span><span class="o">:</span><span class="mi">21</span> <span class="no">PM</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">impl</span><span class="o">.</span><span class="na">WebDriverThreadLocalContainer</span> <span class="n">createDriver</span> <span class="nl">INFO:</span> <span class="nc">Create</span> <span class="nl">webdriver:</span> <span class="mi">1</span> <span class="o">-&gt;</span> <span class="nl">FirefoxDriver:</span> <span class="n">firefox</span> <span class="n">on</span> <span class="nf">MAC</span> <span class="o">(</span><span class="mi">3</span><span class="n">e54e3de</span><span class="o">-</span><span class="n">b212</span><span class="o">-</span><span class="mi">2</span><span class="n">a45</span><span class="o">-</span><span class="mi">93</span><span class="n">ad</span><span class="o">-</span><span class="mi">712</span><span class="n">aae6ee853</span><span class="o">)</span> </code></pre></div></div> <p>To make it more readable (if you haven’t yet configured JUL in your project), you can add the following line in the beginning of your tests:</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">"java.util.logging.SimpleFormatter.format"</span><span class="o">,</span> <span class="s">"%1$tT %4$s %5$s%6$s%n"</span><span class="o">);</span> </code></pre></div></div> <p>If you prefer <code class="language-plaintext highlighter-rouge">slf4j</code>, just add dependency <code class="language-plaintext highlighter-rouge">org.slf4j:jul-to-slf4j:1.7.12</code> to your project and these lines in the beginning of your tests:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">SLF4JBridgeHandler</span><span class="o">.</span><span class="na">removeHandlersForRootLogger</span><span class="o">();</span> <span class="nc">SLF4JBridgeHandler</span><span class="o">.</span><span class="na">install</span><span class="o">();</span> </code></pre></div></div> <p>Now Selenide logs will look better:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="mi">22</span><span class="o">:</span><span class="mi">48</span><span class="o">:</span><span class="mi">15</span> <span class="no">INFO</span> <span class="nl">INFO:</span> <span class="nc">Create</span> <span class="nl">webdriver:</span> <span class="mi">1</span> <span class="o">-&gt;</span> <span class="nl">FirefoxDriver:</span> <span class="n">firefox</span> <span class="n">on</span> <span class="nf">MAC</span> <span class="o">(</span><span class="mi">3</span><span class="n">e54e3de</span><span class="o">-</span><span class="n">b212</span><span class="o">-</span><span class="mi">2</span><span class="n">a45</span><span class="o">-</span><span class="mi">93</span><span class="n">ad</span><span class="o">-</span><span class="mi">712</span><span class="n">aae6ee853</span><span class="o">)</span> </code></pre></div></div> <p>See <a href="https://github.com/selenide/selenide/issues/195">Issue 195</a></p> <h2 id="fixed-cookies-usage-when-downloading-file">Fixed Cookies usage when downloading file</h2> <p>Thank you <a href="https://github.com/philipp-kolesnikov">@philipp-kolesnikov</a> for this <a href="https://github.com/selenide/selenide/pull/191">pull request</a>!</p> <h2 id="added-support-for-element-collections-to-page-objects">Added support for element collections to Page Objects</h2> <p>Now you can declare an elements collection in your page object:</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">SearchResultsPage</span> <span class="o">{</span> <span class="nd">@FindBy</span><span class="o">(</span><span class="n">css</span> <span class="o">=</span> <span class="s">"#ires li.g"</span><span class="o">)</span> <span class="kd">private</span> <span class="nc">ElementsCollection</span> <span class="n">results</span><span class="o">;</span> </code></pre></div></div> <p>See <a href="https://github.com/selenide/selenide/issues/186">Issue 186</a></p> <p>Thank you <a href="https://github.com/rishaselfing">@rishaselfing</a> for the suggestion!</p> <p>P.S. Let me remind that it’s probably simpler to write page objects without annotations:</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">SearchResultsPage</span> <span class="o">{</span> <span class="kd">private</span> <span class="nc">ElementsCollection</span> <span class="n">results</span> <span class="o">=</span> <span class="err">$$</span><span class="o">(</span><span class="s">"#ires li.g"</span><span class="o">);</span> </code></pre></div></div> <h2 id="method-selectshouldhavetext-now-checks-the-selected-option">Method $(“select”).shouldHave(text(“…”)) now checks the selected option</h2> <p>Up to now, the <code class="language-plaintext highlighter-rouge">$("select").shouldHave(text("..."))</code> check was quite useless, because it checked texts of <strong>all</strong> <code class="language-plaintext highlighter-rouge">&lt;option&gt;</code> elements, not only selected ones. Now it checks only texts of <strong>selected</strong> option(s).</p> <p>And method <code class="language-plaintext highlighter-rouge">$("select").getText()</code> returns only texts of selected option(s).</p> <p>See <a href="https://github.com/selenide/selenide/issues/134">Issue 134</a></p> <h2 id="added-method-for-taking-screenshot-of-one-element-or-region">Added method for taking screenshot of one element or region</h2> <p>Sometimes screenshots appear to be useless. When page is too big, the required element does not always fit to the screenshot. In this case you can find useful the new function for taking screenshot of one element.</p> <p>It’s so easy to use:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">File</span> <span class="n">screenshot</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">"#some-div"</span><span class="o">).</span><span class="na">screenshot</span><span class="o">();</span> </code></pre></div></div> <p>See <a href="https://github.com/selenide/selenide/issues/66">Issue 66</a></p> <h2 id="all-methods-string--made-deprecated">All methods <code class="language-plaintext highlighter-rouge">$(String, ...)</code> made deprecated</h2> <p>Please be sure that you don’t use deprecated methods. We are going to remove then in one of next Selenide versions (probably in Selenide 3.0).</p> <p>Now there is a better way to add explanation to your checks using <code class="language-plaintext highlighter-rouge">because</code> function:</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">text</span><span class="o">(</span><span class="s">"Some wrong test"</span><span class="o">).</span><span class="na">because</span><span class="o">(</span><span class="s">"it's wrong text"</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">waitUntil</span><span class="o">(</span><span class="n">hidden</span><span class="o">.</span><span class="na">because</span><span class="o">(</span><span class="s">"it's sensitive information"</span><span class="o">),</span> <span class="mi">100</span><span class="o">);</span> </code></pre></div></div> <h2 id="removed-cglib-nodep-from-selenide-dependencies">Removed cglib-nodep from Selenide dependencies</h2> <p>We found what <code class="language-plaintext highlighter-rouge">cglib-nodep</code> dependency is too old and useless. And it can sometimes conflict with other project dependencies. It seems that it doesn’t support Java 8 and haven’t been updated for 5 years.</p> <p>So we removed cglib-nodep from Selenide dependencies.</p> <p>If you still need cglib-nodep for some reason, just add dependency <code class="language-plaintext highlighter-rouge">cglib:cglib-nodep:jar:3.1</code> to your project.</p> <p><br /></p> <h1 id="i-need-your-help">I need your help!</h1> <p>Please vote for my submission to SeleniumConf 2015 conference <a href="http://confengine.com/selenium-conf-2015/proposal/1294/selenide-concise-ui-tests-in-java">here</a>!</p> <p><br /></p> <p>And what’s up with you?</p> <p><br /></p> <p>Andrei Solntsev</p> <p>selenide.org</p> https://selenide.org/2015/07/27/selenide-2.20/ https://selenide.org/2015/07/27/selenide-2.20 2015-07-27T00:00:00+00:00 Changes in Selenide 2.19 <p>Hi everybody!</p> <p>We have released Selenide 2.19.</p> <p>Several problems have been fixed, primarily with inner frames and self-signed certificates.</p> <h2 id="working-with-inner-frames">Working with inner frames</h2> <p>One of the most problematic objects for automated testing is <strong>frames</strong>.</p> <p>Selenium Webdriver can switch to frame. But there are also inner frames in the field! Webdriver cannot switch into inner frame. Poor testers need to switch to parent frame, then to child frame, then to grandchild frame, etc.</p> <p>In Selenide 2.19 we added a convenient method for switching directly into inner frame. Just as simple:</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="n">switchTo</span><span class="o">().</span><span class="na">innerFrame</span><span class="o">(</span><span class="s">"parentFrame"</span><span class="o">,</span> <span class="s">"childFrame_2"</span><span class="o">,</span> <span class="s">"childFrame_2_1"</span><span class="o">);</span> </code></pre></div></div> <p>By the way, searching of frame also works faster than in Selenium because of optimized locators usage.</p> <blockquote> <p>Thanks to @dimand58 for this pull request!</p> </blockquote> <h2 id="phantomjs-can-now-work-with-self-signed-certificates">PhantomJS can now work with self-signed certificates</h2> <p>Another problematic aspect for automation are self-signed certificates.</p> <p>This is when your administrators desire security. They run your web application for testing on <strong>https</strong> (like https://test.company.ru). But they do not have enough money to use real trusted SSL certificated. And they use <strong>self-signed</strong> (aka <strong>untrusted</strong>) certificates on test-servers (that are typically available only in intranet).</p> <p>As a result, we do not get any better security, but get infinite problems like “browser shows warnings”, “my script cannot download files”, “script cannot open application in IE” etc.</p> <p>Webdriver providers try to make our life even more complex. There is standard webdriver setting <code class="language-plaintext highlighter-rouge">"acceptSslCerts"</code>, which is understood by Chrome, FireFox and even htmlunit. But not PhantomJS. PhantomJS doesn’t understand this setting, it wants you to configure its own specific setting! And finally, IE doesn’t understand any settings.</p> <p>We have done it. We configured the right settings, and now PhantomJS+Selenide can open your “https://test.company.ru”.</p> <p>But IE still doesn’t work with self-signed https. Feel free to share your knowledge if you know how to cure it.</p> <h2 id="method-download-now-supports-self-signed-certs">Method <code class="language-plaintext highlighter-rouge">$.download()</code> now supports self-signed certs</h2> <p>In case you didn’t know, Selenide has a very convenient method for file downloading:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><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> </code></pre></div></div> <p>Now it also works when you try to download file from your mega-secure untrusted “<strong>https</strong>://test.company.ru”.</p> <h2 id="method-setvalue-also-triggers-focus-event">Method <code class="language-plaintext highlighter-rouge">$.setValue()</code> also triggers “focus” event</h2> <p>Before this, method <code class="language-plaintext highlighter-rouge">$.setValue()</code> (in <code class="language-plaintext highlighter-rouge">fastSetValue=true</code> mode) triggered events “keydown”, “keypress”, “input”, “keyup”, “change”. Now it also triggers “focus”. I am not actually sure that it’s really needed, added just in case.</p> <h2 id="fixed-bug-with-screenshots-in-selenide-218">Fixed bug with screenshots in Selenide 2.18</h2> <p>Selenide 2.18 introduced one bug: it took too many of screenshots. Even if tests didn’t failed. It didn’t cause test failure, but took more disk space. Now it’s fixed.</p> <h2 id="upgraded-to-selenium-webdriver-2460">Upgraded to Selenium Webdriver 2.46.0</h2> <p><a href="https://raw.githubusercontent.com/SeleniumHQ/selenium/master/java/CHANGELOG">Changelog of 2.46.0</a> is quite impressive.</p> <ul> <li>Added beta-version of Marionette webdriver (Firefox webdriver reincarnation?)</li> <li>In some cases, selenium server should start 10x times faster</li> <li>Native events not supported anymore in Firefox 33+</li> <li>Presto-based Opera not supported anymore</li> <li>Etc.</li> </ul> <p><br /></p> <p>And what’s up with you?</p> <p><br /></p> https://selenide.org/2015/06/21/selenide-2.19/ https://selenide.org/2015/06/21/selenide-2.19 2015-06-21T00:00:00+00:00 Changes in Selenide 2.18 <p>Good evening!</p> <p>In the end of April we released long-waited Selenide 2.18. It was hard. We have totally rewritten waiting algorithm, so now it catches all the StaleElementException.</p> <p>Let me describe it in details.</p> <h2 id="waiting-algorithm">Waiting algorithm</h2> <p>Selenide always fought against StaleElementException and other problems caused by Ajax and timeouts. But it was still possible to get StaleElementException in rare cases.</p> <p>In Selenide 2.18 we reworked waiting mechanism.</p> <p>The old algorithm was the following:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">waitForElement</span><span class="o">().</span><span class="na">click</span><span class="o">()</span> </code></pre></div></div> <p>Selenide waited until the element got visible, and only then performed required action (click in this example). In other words, the action was “two-phased”. And sometimes (especially in SPA applications) it could happen that the first phase has completed correctly (element was visible at that moment), but during the second phase (click in this example) element disappeared.</p> <p>The new algorithm is the following:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">while</span> <span class="o">(</span><span class="n">errors</span> <span class="n">and</span> <span class="o">&lt;</span><span class="mi">4</span> <span class="n">seconds</span><span class="o">)</span> <span class="o">{</span> <span class="n">element</span><span class="o">.</span><span class="na">click</span><span class="o">()</span> <span class="o">}</span> </code></pre></div></div> <p>This algorithm is faster, because it performs only one action for most elements (that do not disappear either appear). And probability of StaleElementException is much less (though, still non zero :().</p> <h2 id="screenshots">Screenshots</h2> <p>Now Selenide takes screenshot after any failure. In previous versions, Selenide did not take screenshots, say, in case of selenium errors (e.g. method <code class="language-plaintext highlighter-rouge">click()</code> failed because element was not clickable).</p> <h2 id="method-shouldhavevaluejohn-now-ignores-invisible-characters-spaces-tabs-newlines">Method <code class="language-plaintext highlighter-rouge">$.shouldHave(value("john"))</code> now ignores invisible characters (spaces, tabs, newlines).</h2> <p>It’s useful e.g. because numbers can be formatted with spaces or non-breakable spaces. Visually there is not difference. And user cannot see any difference. So, test must not too.</p> <p>If you still need to verify exact value of element, you can use a special check: <code class="language-plaintext highlighter-rouge">$.shouldHave(exactValue(" john "))</code>.</p> <h2 id="clicking-with-javascript">Clicking with JavaScript</h2> <p>Now we have added a special “clicking mode”, in which click is performed with JavaScript (instead of default “native” browser click).</p> <p><a href="https://github.com/selenide/selenide/pull/174">They say</a>, it can be useful for running tests in IE, because IE doesn’t always properly click elements.</p> <p>You can enable the new mode with property: <code class="language-plaintext highlighter-rouge">-Dselenide.click-via-js=true</code></p> <blockquote> <p>Thanks to @dimand58 for this pull request!</p> </blockquote> <h2 id="added-method-doubleclick">Added method <code class="language-plaintext highlighter-rouge">$.doubleClick()</code></h2> <p>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">".modal-popup"</span><span class="o">).</span><span class="na">doubleClick</span><span class="o">();</span><span class="err">`</span> </code></pre></div></div> <h2 id="methods-hover-contextclick-draganddropto-now-can-be-chained">Methods <code class="language-plaintext highlighter-rouge">$.hover()</code>, <code class="language-plaintext highlighter-rouge">$.contextClick()</code>, <code class="language-plaintext highlighter-rouge">$.dragAndDropTo()</code> now can be <em>chained</em></h2> <p>It means, you can use them in 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">"#username"</span><span class="o">).</span><span class="na">hover</span><span class="o">().</span><span class="na">contextClick</span><span class="o">().</span><span class="na">doubleClick</span><span class="o">();</span> </code></pre></div></div> <h2 id="fixed-sizzle-selectors-on-pages-without-jquery">Fixed Sizzle selectors on pages without jQuery</h2> <blockquote> <p>Thanks to @Gert for this pull request!</p> </blockquote> <h2 id="added-method-webdriverrunnerhaswebdriverstarted">Added method <code class="language-plaintext highlighter-rouge">WebDriverRunner.hasWebDriverStarted()</code></h2> <p>It can be useful, say, when you want to take screenshots or perform some other custom actions with webdriver in your tests.</p> <blockquote> <p>Thanks to @dimand58 for this pull request!</p> </blockquote> <h2 id="method-setvalue-in-fastsetvalue-mode-now-triggers-input-event">Method <code class="language-plaintext highlighter-rouge">$.setValue()</code> in <code class="language-plaintext highlighter-rouge">fastSetValue</code> mode now triggers <code class="language-plaintext highlighter-rouge">input</code> event</h2> <p>Now <code class="language-plaintext highlighter-rouge">$.setValue()</code> in <code class="language-plaintext highlighter-rouge">fastSetValue</code> mode triggers the following events:</p> <ul> <li><code class="language-plaintext highlighter-rouge">keydown</code></li> <li><code class="language-plaintext highlighter-rouge">keypress</code></li> <li><code class="language-plaintext highlighter-rouge">input</code></li> <li><code class="language-plaintext highlighter-rouge">keyup</code></li> <li><code class="language-plaintext highlighter-rouge">change</code></li> </ul> <p>It fixed autocompletion in some applications, and also filling of textarea. I hope that now <code class="language-plaintext highlighter-rouge">$.sendKeys()</code> can be totally replaced by fast method <code class="language-plaintext highlighter-rouge">$.setaValue()</code>.</p> <p>Could you do that?</p> <h2 id="now-selenide-depends-on-latest-version-of-commons-codec-110">Now Selenide depends on latest version of commons-codec 1.10</h2> <p>Previously Selenide downloaded (transitively from selenium-java) an old version of commons-codec 1.6 It could create problems for applications that wanted to use latest commons-codec.</p> <h2 id="let-me-brag">Let me brag</h2> <p>Finally is the desert: fresh download statistics from maven central repository.</p> <p>There is becoming more of us!</p> <p>Number of unique IP:</p> <center> <img src="/images/2015/05/selenide_downloads_unique_ips.png" width="800" /> </center> <p><br /></p> <p>And number of downloads:</p> <center> <img src="/images/2015/05/selenide_downloads.png" width="800" /> </center> <p><br /></p> <p>And what’s up with you?</p> <p><br /></p> https://selenide.org/2015/05/06/selenide-2.18/ https://selenide.org/2015/05/06/selenide-2.18 2015-05-06T00:00:00+00:00 Changes in Selenide 2.16 and 2.17 <p>Hi Seleniders!</p> <p>We haven’t written to blog for a while. There have been released 3 new versions of Selenide during this period.</p> <p>Let me describe changes in versions 2.16 and 2.17</p> <h3 id="soft-asserts">Soft asserts</h3> <p>We finally added SoftAsserts to Selenide. I am still not sure that it’s a good idea, but it was asked a lot. :)</p> <p>In SoftAssert mode your tests do not fail immediately, but all the checks like <code class="language-plaintext highlighter-rouge">$.shouldHave(text("xxx"))</code> will collect errors and report all them at once in the end of test. It allows you to collect all the fails, fix them all and re-run test only once. It could be useful if cost of running tests is too big for you.</p> <p>To enable Soft asserts in JUnit (see <a href="https://selenide.org/javadoc/current/com/codeborne/selenide/junit/SoftAsserts.html">documentation</a>):</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">SoftAssertJUnitTest</span> <span class="o">{</span> <span class="nd">@Rule</span> <span class="kd">public</span> <span class="nc">SoftAsserts</span> <span class="n">softAsserts</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">SoftAsserts</span><span class="o">();</span> </code></pre></div></div> <p>To enable Soft asserts in TestNG (see. <a href="https://selenide.org/javadoc/current/com/codeborne/selenide/testng/SoftAsserts.html">documentation</a>):</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">SoftAsserts</span><span class="o">.</span><span class="na">class</span><span class="o">)</span> <span class="kd">public</span> <span class="kd">class</span> <span class="nc">SoftAssertTestNGTest</span> <span class="o">{</span> </code></pre></div></div> <p>And here is the result.</p> <p>In the end of test, it shows all the collected errors:</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">AssertionError</span><span class="o">:</span> <span class="nc">Test</span> <span class="nf">userCanUseSoftAssertWithJUnit</span><span class="o">(</span><span class="n">integration</span><span class="o">.</span><span class="na">SoftAssertJUnitTest</span><span class="o">)</span> <span class="n">failed</span><span class="o">.</span> <span class="mi">3</span> <span class="n">checks</span> <span class="n">failed</span> <span class="no">FAIL</span> <span class="err">#</span><span class="mi">1</span><span class="o">:</span> <span class="nc">Element</span> <span class="n">should</span> <span class="n">have</span> <span class="n">attribute</span> <span class="n">value</span><span class="o">=</span><span class="mi">777</span> <span class="o">{</span><span class="err">#</span><span class="n">radioButtons</span> <span class="n">input</span><span class="o">}</span> <span class="nl">Element:</span> <span class="err">'</span><span class="o">&lt;</span><span class="n">input</span> <span class="n">name</span><span class="o">=</span><span class="s">"me"</span> <span class="n">type</span><span class="o">=</span><span class="s">"radio"</span> <span class="n">value</span><span class="o">=</span><span class="s">"master"</span><span class="o">&gt;&lt;/</span><span class="n">input</span><span class="o">&gt;</span><span class="err">'</span> <span class="nl">Screenshot:</span> <span class="nl">file:</span><span class="o">/</span><span class="nc">Users</span><span class="o">/</span><span class="n">andrei</span><span class="o">/</span><span class="n">projects</span><span class="o">/</span><span class="n">selenide</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">integration</span><span class="o">/</span><span class="nc">SoftAssertJUnitTest</span><span class="o">/</span><span class="n">userCanUseSoftAssertWithJUnit</span><span class="o">/</span><span class="mf">1425503251321.0</span><span class="o">.</span><span class="na">png</span> <span class="nl">Timeout:</span> <span class="mi">0</span> <span class="n">ms</span><span class="o">.</span> <span class="no">FAIL</span> <span class="err">#</span><span class="mi">2</span><span class="o">:</span> <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">radioButtons</span> <span class="n">select</span><span class="o">}</span> <span class="nl">Expected:</span> <span class="n">visible</span> <span class="nl">Screenshot:</span> <span class="nl">file:</span><span class="o">/</span><span class="nc">Users</span><span class="o">/</span><span class="n">andrei</span><span class="o">/</span><span class="n">projects</span><span class="o">/</span><span class="n">selenide</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">integration</span><span class="o">/</span><span class="nc">SoftAssertJUnitTest</span><span class="o">/</span><span class="n">userCanUseSoftAssertWithJUnit</span><span class="o">/</span><span class="mf">1425503252361.1</span><span class="o">.</span><span class="na">png</span> <span class="nl">Timeout:</span> <span class="mi">0</span> <span class="n">ms</span><span class="o">.</span> <span class="nc">Caused</span> <span class="nl">by:</span> <span class="nl">NoSuchElementException:</span> <span class="nc">Unable</span> <span class="n">to</span> <span class="n">locate</span> <span class="nl">element:</span> <span class="o">{</span><span class="s">"method"</span><span class="o">:</span><span class="s">"css selector"</span><span class="o">,</span><span class="s">"selector"</span><span class="o">:</span><span class="s">"#radioButtons select"</span><span class="o">}</span> <span class="no">FAIL</span> <span class="err">#</span><span class="mi">3</span><span class="o">:</span> <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">xxx</span><span class="o">}</span> <span class="nl">Expected:</span> <span class="n">visible</span> <span class="nl">Screenshot:</span> <span class="nl">file:</span><span class="o">/</span><span class="nc">Users</span><span class="o">/</span><span class="n">andrei</span><span class="o">/</span><span class="n">projects</span><span class="o">/</span><span class="n">selenide</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">integration</span><span class="o">/</span><span class="nc">SoftAssertJUnitTest</span><span class="o">/</span><span class="n">userCanUseSoftAssertWithJUnit</span><span class="o">/</span><span class="mf">1425503252697.2</span><span class="o">.</span><span class="na">png</span> <span class="nl">Timeout:</span> <span class="mi">0</span> <span class="n">ms</span><span class="o">.</span> <span class="nc">Caused</span> <span class="nl">by:</span> <span class="nl">NoSuchElementException:</span> <span class="nc">Unable</span> <span class="n">to</span> <span class="n">locate</span> <span class="nl">element:</span> <span class="o">{</span><span class="s">"method"</span><span class="o">:</span><span class="s">"css selector"</span><span class="o">,</span><span class="s">"selector"</span><span class="o">:</span><span class="s">"#xxx"</span><span class="o">}</span> <span class="n">at</span> <span class="n">org</span><span class="o">.</span><span class="na">junit</span><span class="o">.</span><span class="na">Assert</span><span class="o">.</span><span class="na">fail</span><span class="o">(</span><span class="nc">Assert</span><span class="o">.</span><span class="na">java</span><span class="o">:</span><span class="mi">88</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">junit</span><span class="o">.</span><span class="na">SoftAsserts</span><span class="o">.</span><span class="na">after</span><span class="o">(</span><span class="nc">SoftAsserts</span><span class="o">.</span><span class="na">java</span><span class="o">:</span><span class="mi">54</span><span class="o">)</span> <span class="n">at</span> <span class="n">org</span><span class="o">.</span><span class="na">junit</span><span class="o">.</span><span class="na">rules</span><span class="o">.</span><span class="na">ExternalResource</span><span class="err">$</span><span class="mi">1</span><span class="o">.</span><span class="na">evaluate</span><span class="o">(</span><span class="nc">ExternalResource</span><span class="o">.</span><span class="na">java</span><span class="o">:</span><span class="mi">50</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">intellij</span><span class="o">.</span><span class="na">rt</span><span class="o">.</span><span class="na">execution</span><span class="o">.</span><span class="na">application</span><span class="o">.</span><span class="na">AppMain</span><span class="o">.</span><span class="na">main</span><span class="o">(</span><span class="nc">AppMain</span><span class="o">.</span><span class="na">java</span><span class="o">:</span><span class="mi">134</span><span class="o">)</span> </code></pre></div></div> <h3 id="profiler">Profiler</h3> <p>Now Selenide can create a report about all actions performed during the test. The report includes execution time of every action in milliseconds. It allows you better understand what happens, and what steps take too much time.</p> <p>Here is an example report:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>+--------------------+--------------------------------------------+----------+----------+ |Element |Subject |Status |ms. | +--------------------+--------------------------------------------+----------+----------+ |open |http://0.0.0.0:23762/page_jquery.html |PASSED |131 | |#multirowTable |find elements(by text: Chack) |PASSED |100 | |#multirowTable tr |find elements(by text: Chack) |PASSED |100 | |#multirowTable tr |find(by text: Chack) |PASSED |0 | |by text: Chack |get attribute(class) |PASSED |139 | +--------------------+--------------------------------------------+----------+----------+ </code></pre></div></div> <p>To enable this report, you need to add the following rule to your tests:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Rule</span> <span class="kd">public</span> <span class="nc">TestRule</span> <span class="n">prettyReportCreator</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">PrettyReportCreator</span><span class="o">();</span> </code></pre></div></div> <p>This is an experimental functionality. Only JUnit is supported by now.</p> <p>Please try it and give your feedback.</p> <blockquote> <p>Thanks to <a href="https://github.com/kumarunster">kumarunster</a> for this pull request!</p> </blockquote> <p><br /></p> <h3 id="fixed-function-closest">Fixed function <code class="language-plaintext highlighter-rouge">$.closest()</code></h3> <p>Now the search for parent element by CSS class works correctly:</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">"firstName"</span><span class="o">)).</span><span class="na">closest</span><span class="o">(</span><span class="s">".active"</span><span class="o">);</span> </code></pre></div></div> <p><br /></p> <h3 id="method-tostring-now-logs-all-attributes">Method <code class="language-plaintext highlighter-rouge">$.toString()</code> now logs all attributes</h3> <p>Method <code class="language-plaintext highlighter-rouge">$.toString()</code> logged only defined set of attributes: <code class="language-plaintext highlighter-rouge">id</code>, <code class="language-plaintext highlighter-rouge">class</code>, <code class="language-plaintext highlighter-rouge">type</code> etc. The problem is that Selenium webdriver doesn’t provide API for listing all attributes.</p> <p>But we found a way! Now method <code class="language-plaintext highlighter-rouge">$.toString()</code> prints out all attributes (using JavaScript hack):</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">assertEquals</span><span class="o">(</span><span class="s">"&lt;div class=\"invisible-with-multiple-attributes\" "</span> <span class="o">+</span> <span class="s">"data-animal-id=\"111\" id=\"gopher\" ng-class=\"widget\" ng-click=\"none\" "</span> <span class="o">+</span> <span class="s">"onchange=\"console.log(this);\" onclick=\"void(0);\" placeholder=\"Animal\" "</span> <span class="o">+</span> <span class="s">"displayed:false&gt;&lt;/div&gt;"</span><span class="o">,</span> <span class="err">$</span><span class="o">(</span><span class="s">"#gopher"</span><span class="o">).</span><span class="na">toString</span><span class="o">());</span> </code></pre></div></div> <h3 id="upgraded-to-selenium-2450">Upgraded to <a href="https://raw.githubusercontent.com/SeleniumHQ/selenium/master/java/CHANGELOG">Selenium 2.45.0</a>.</h3> <p>Please note that this release disables native events in Firefox.</p> <p><br /></p> <p>And what’s up with you?</p> <p><br /></p> https://selenide.org/2015/05/05/selenide-2.16-and-2.17/ https://selenide.org/2015/05/05/selenide-2.16-and-2.17 2015-05-05T00:00:00+00:00 How to test GMail <p>Hi all!</p> <p>How would you test GMail if you were Google developer? It’s a great exercise, try it once!</p> <p>Automated testing of GMail is not trivial. It heavily uses ajax, elements are loaded dynamically, loading may take more than few seconds, and there is no reasonable IDs/selectors. You would need to add “wait” for almost every operator!</p> <h3 id="project-gmail-test">Project “GMail test”</h3> <p>But it’s possible! In <a href="https://github.com/selenide-examples">Selenide Examples</a> series we present a <a href="https://github.com/selenide-examples/gmail">github project for testing GMail</a>. It checks inbox content and composes a new message. Then it clicks “Undo”, edits the message body and sends it again. And finally waits until the “Undo” button disappears.</p> <h3 id="video">Video</h3> <p>Here is a short video for demonstrating how it works:</p> <iframe src="//player.vimeo.com/video/115448433" width="800" height="526" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe> <h2 id="lets-analyze-this">Let’s analyze this</h2> <p>Here is the github project: https://github.com/selenide-examples/gmail</p> <p>Let’s take a look under the hood!</p> <h3 id="settings">Settings</h3> <p>Before test run we need to set longer timeout, because GMail element tend to load longer than 4 seconds (which is a default timeout in Selenide). Let’s set 10 seconds. Though at some conferences with slow WiFi even 10 was not sufficient long.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nd">@BeforeClass</span> <span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">openInbox</span><span class="o">()</span> <span class="o">{</span> <span class="n">timeout</span> <span class="o">=</span> <span class="mi">10000</span><span class="o">;</span> <span class="n">baseUrl</span> <span class="o">=</span> <span class="s">"http://gmail.com"</span><span class="o">;</span> <span class="n">open</span><span class="o">(</span><span class="s">"/"</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">"Loading"</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="n">login</span><span class="o">();</span> <span class="o">}</span> </code></pre></div></div> <p>Have you noticed how we wait until the page gets loaded? This show the power of Selenide: it’s easy to find element by text, and it’s easy to wait until it disappears.</p> <h3 id="login">Login</h3> <p>Performing user login is easy:</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="kt">void</span> <span class="nf">login</span><span class="o">()</span> <span class="o">{</span> <span class="err">$</span><span class="o">(</span><span class="s">"#Email"</span><span class="o">).</span><span class="na">val</span><span class="o">(</span><span class="nc">System</span><span class="o">.</span><span class="na">getProperty</span><span class="o">(</span><span class="s">"gmail.username"</span><span class="o">,</span> <span class="s">"enter-your-gmail-username"</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">"#Passwd"</span><span class="o">).</span><span class="na">val</span><span class="o">(</span><span class="nc">System</span><span class="o">.</span><span class="na">getProperty</span><span class="o">(</span><span class="s">"gmail.password"</span><span class="o">,</span> <span class="s">"enter-your-gmail-password"</span><span class="o">));</span> <span class="err">$</span><span class="o">(</span><span class="s">"#signIn"</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">".error-msg"</span><span class="o">).</span><span class="na">waitUntil</span><span class="o">(</span><span class="n">disappears</span><span class="o">,</span> <span class="mi">2000</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>The last line is needed to fail fast if you configured wrong username or password.</p> <h3 id="unread-messages-counter">Unread messages counter</h3> <p>In a real life, I would run tests with a predefined data set. Say, with 4 unread messages. And check for presence of text “Inbox (4)”:</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">showsNumberOfUnreadMessages</span><span class="o">()</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">"//div[@role='navigation']"</span><span class="o">)).</span><span class="na">find</span><span class="o">(</span><span class="n">withText</span><span class="o">(</span><span class="s">"Inbox (4)"</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 our case is harder: we need to test web application with real data that is not constant. Therefore let’s limit ourselves to just check availability of text “Inbox”.)</p> <h3 id="verifying-inbox-content">Verifying inbox content</h3> <p>Unfortunately all the GMail selectors are obfuscated. We cannot ID or other selectors. So, let’s just verify that some texts are present on a page. We know that such messages should be definitely in my inbox:</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">inboxShowsUnreadMessages</span><span class="o">()</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">"Gmail Team"</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">shouldHave</span><span class="o">(</span><span class="n">size</span><span class="o">(</span><span class="mi">1</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">"LastPass"</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">shouldHave</span><span class="o">(</span><span class="n">size</span><span class="o">(</span><span class="mi">3</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">"Pivotal Tracker"</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">shouldHave</span><span class="o">(</span><span class="n">size</span><span class="o">(</span><span class="mi">3</span><span class="o">));</span> <span class="o">}</span> </code></pre></div></div> <h3 id="refreshing-inbox">Refreshing inbox</h3> <p>GMail interface has a “Refresh” button for reloading inbox. Let’s find it by attribute <code class="language-plaintext highlighter-rouge">title</code>=<code class="language-plaintext highlighter-rouge">Refresh</code>.</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">userCanRefreshMessages</span><span class="o">()</span> <span class="o">{</span> <span class="c1">// In a real life:: INSERT INTO messages ...</span> <span class="err">$</span><span class="o">(</span><span class="n">by</span><span class="o">(</span><span class="s">"title"</span><span class="o">,</span> <span class="s">"Refresh"</span><span class="o">)).</span><span class="na">click</span><span class="o">();</span> <span class="c1">// In a real life: verify that the new message has appeared in the inbox</span> <span class="o">}</span> </code></pre></div></div> <p>In a real project I would add a new message into database, and verify that the new message has appeared in the inbox after pressing “Refresh” button.</p> <h3 id="new-message">New message</h3> <p>To compose a new message, let’s click the “COMPOSE” button:</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">byText</span><span class="o">(</span><span class="s">"COMPOSE"</span><span class="o">)).</span><span class="na">click</span><span class="o">();</span> </code></pre></div></div> <p>Enter recipient address, subject and text:</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">"to"</span><span class="o">)).</span><span class="na">val</span><span class="o">(</span><span class="s">"andrei.solntsev@gmail.com"</span><span class="o">).</span><span class="na">pressTab</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">"placeholder"</span><span class="o">,</span> <span class="s">"Subject"</span><span class="o">)).</span><span class="na">val</span><span class="o">(</span><span class="s">"ConfetQA demo!"</span><span class="o">).</span><span class="na">pressTab</span><span class="o">();</span> <span class="err">$</span><span class="o">(</span><span class="s">".editable"</span><span class="o">).</span><span class="na">val</span><span class="o">(</span><span class="s">"Hello braza!"</span><span class="o">).</span><span class="na">pressEnter</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">"Send"</span><span class="o">)).</span><span class="na">click</span><span class="o">();</span> </code></pre></div></div> <p>Isn’t it easy?</p> <p>And finally, let’s verify that the message has been sent:</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">withText</span><span class="o">(</span><span class="s">"Your message has been sent."</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> <h3 id="undo---redo">Undo - redo</h3> <p>There is a very cool (but <em>experimental</em>) feature in GMail - “Undo”. After an email has been sent, you can undo it during next 10 seconds. By clicking the “Undo” button, user can cancel sending the last message and go back to editing. It’s incredibly useful when, say, you sent message to a wrong recipient.</p> <p>So, let’s try to test “Undo” feature. In the end of previous test, let’s add the following lines:</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">byText</span><span class="o">(</span><span class="s">"Undo"</span><span class="o">)).</span><span class="na">click</span><span class="o">();</span> <span class="n">highlight</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">"Sending has been undone."</span><span class="o">)).</span><span class="na">should</span><span class="o">(</span><span class="n">appear</span><span class="o">));</span> </code></pre></div></div> <p>Edit the message body and send 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">".editable"</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="na">append</span><span class="o">(</span><span class="s">"Hello from ConfetQA Selen"</span><span class="o">).</span><span class="na">pressEnter</span><span class="o">().</span><span class="na">pressEnter</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">"Send"</span><span class="o">)).</span><span class="na">click</span><span class="o">();</span> </code></pre></div></div> <p>And finally wait for 10 seconds until the “Undo” button disappears:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">highlight</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">"Your message has been sent."</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="n">highlight</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">"Undo"</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="na">waitUntil</span><span class="o">(</span><span class="n">disappears</span><span class="o">,</span> <span class="mi">12000</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">"Sent Mail"</span><span class="o">)).</span><span class="na">click</span><span class="o">();</span> </code></pre></div></div> <p>The message has been finally sent.</p> <p>Now GMail is tested. Google can sleep peacefully. :)</p> <h2 id="findings">Findings</h2> <p>As you see, web interface without IDs can also be tested. Long loading time and ajax requests are not obstacles. Dynamic content is not stopper. The following are simple receipts to overcome these problems:</p> <ul> <li><em>Find elements by text</em> <br /> This is how real users behave. This is less dependent on application implementation details.</li> <li><em>Test only important things</em> <br /> There are still a lot of things in GMail that left untested. It seems that it’s not possible to test them (unable to use pre-generated test data in tests, absence of static locators). But it’s not that important - important is the fact that the critical functionality is tested: inbox content and sending new message. Always start from testing functionality that is most critical for business.</li> <li><em>Use appropriate instruments</em> <br /> Selenide automatically resolves problems with timeouts, ajax, dynamic content, searching by text. Tests are not polluted with long scary XPath. Tests contain only business logic. Tests are readable.</li> </ul> <p><br /> Wish you simple tests!</p> <div class="author"> Andrei Solntsev<br /> <a href="https://selenide.org">selenide.org</a> </div> <p><br /></p> https://selenide.org/2014/12/28/how-to-test-gmail/ https://selenide.org/2014/12/28/how-to-test-gmail 2014-12-28T00:00:00+00:00 How to allocate time for refactoring? <p>One of the most common IT questions is: <em>How to allocate time for refactoring</em>?</p> <p>It’s common for both developers and testers. Both get very quickly a heap of dirty unreadable code, a plenty of slow, unmaintainable, unreadable tests. It’s getting harder and harder to live with it. Development/testing is getting slower. Motivation decreases. Sometimes you happen to clean up some lines in the evening time, but… it seems to be something wrong with the evening-time work?..</p> <ul> <li>Where is the justice?</li> <li>Am I the only who needs it?</li> <li>Why doesn’t my boss allocate me time for refactoring?</li> </ul> <p>I know. I also went through it.</p> <h3 id="no-way">No way</h3> <p>Now, let’s face the truth. If somebody comes to me and asks to allocate one week for refactoring, <strong>I will refuse</strong>.</p> <p>Let me explain why. Because refactoring can last endlessly, but somebody should do <em>the work</em>.</p> <p>10 years ago I was hurt to hear this. Now I am saying it by myself. Moreover, I claim that cleaning code at evening hours is not unfairly - it’s <strong>unprofessional</strong>.</p> <p>So, have I lost my ideal?</p> <h3 id="absolutely-not">Absolutely not.</h3> <p>Exactly the opposite. Now I am pretty sure that refactoring is absolutely required. Code must be continuously cleaned up through thick and thin. It just needs to be performed a little bit differently.</p> <p>You must not ask anybody to allocate a separate time for refactoring. Refactoring is not a separate thing, independent from development/testing. Refactoring <strong>is</strong> part of coding. Refactoring <strong>is</strong> part of writing automated tests. It’s the same natural and necessary part as typing, compilation and run.</p> <p>The following is my receipt:</p> <h2 id="small-steps"><strong>Small steps</strong>!</h2> <p>Recall TDD. Your process should look like this:</p> <ul> <li>Write test (red) - 1 hour</li> <li>Write code (to make test green) - 1 hour</li> <li>Refactor (to make code/tests readable and clean) - 1 hour</li> <li>Make a tea, go to step 1.</li> </ul> <p>This is a continuous process. Small steps. Continuous progress. Hot tea.</p> <p>(Depending on programming language, project and people “1 hour” can be replaced by “5 minutes” or whatever else.)</p> <h3 id="but-what-my-boss-would-think-about-it">But what my boss would think about it?</h3> <p>Nobody will blame you that you are wasting time, <strong>if</strong> you show <strong>continuous progress</strong>. If you create new features every day. In case of testers - create new automated tests every day.</p> <blockquote> <p>Nobody ever got fired for doing feature in 6 hours instead of 5 hours.</p> </blockquote> <p>Think about it. You boss does not know exactly, how long this feature should be implemented. It means that he can never prove that you wasted additional time for writing tests or refactoring. The opposite is also true - you cannot prove (with facts and numbers) that refactoring speeds up the development time. Both of you can prove nothing. So, just work so as you believe is good to work.</p> <p>Don’t get me wrong, I am not calling for sabotage. I am not calling for doing your job longer than needed. Just opposite: I believe that this simple receipt lets you do your job faster:</p> <blockquote> <p>Small steps: Test. Code. Refactor.</p> </blockquote> <h3 id="so-i-dont-need-to-ask-for-permission">So, I don’t need to ask for permission?</h3> <p>If somebody comes to me asking to allocate time for refactoring, I will reject. For the very simple reason: he does not know the <em>TDD mantra</em>. He will almost certainly <em>refucktor</em> this week, and nothing gets remarkably better as a result.</p> <p>Good doctor doesn’t ask permission to wash his hands before a surgery. Good artist doesn’t ask permission to spend time for tuning his instrument. Somehow all the people understand that this is needed. Without <em>wasting time</em> on washing hands and tuning the instrument, they just cannot do their job well. So, are you worse, my dear <em>professional</em> developers and testers?</p> <p>But don’t forget that doctor manages to cure at least somebody in a day. And artist manages to play at least few songs per concert. That’s why refactoring for a week, and not refactoring at all are both bad.</p> <p>Small steps. Continuous progress. Tea with ginger.</p> <p>And with cookies.</p> <p><br /></p> https://selenide.org/2014/12/17/time-for-refactoring/ https://selenide.org/2014/12/17/time-for-refactoring 2014-12-17T00:00:00+00:00 The fast and the continuous @ SQA Days 16 <p>This is a video from my presentation <a href="http://sqadays.com/ru/talk/25882">“The fast and the continuous”</a> on the last SQA Days 16 conference in Saint-Petersburg (Russia).</p> <p>The video is in Russian.</p> <iframe src="//player.vimeo.com/video/114339032" width="800" height="256" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe> <p><a href="https://vimeo.com/114339032">The fast and the continuous</a> from <a href="https://vimeo.com/orlikov">Vlad Orlikov</a> on <a href="https://vimeo.com">Vimeo</a>.</p> <p>Video of Andrei Solntsev presentation on SQA Days-16<br /> November 14-15 2014, Saint-Petersburg, Russia<br /> www.sqadays.com</p> <p><br /></p> https://selenide.org/2014/12/13/the-fast-and-the-continuous/ https://selenide.org/2014/12/13/the-fast-and-the-continuous 2014-12-13T00:00:00+00:00 You find wrong bugs <p>When I was on the last SQA Days conference in Saint-Petersburg, there happened an incident. At that moment, I didn’t realize what happened. I just smiled. And only a few days later I got the idea.</p> <h3 id="so">So,</h3> <p>when I finished <a href="http://sqadays.com/ru/talk/25882">my speech</a> about really effective automated testing, a man took a microphone and started asking criticizing questions. After a few answers of mine, he sat down discordant, saying:</p> <blockquote> <p>You find wrong bugs.</p> </blockquote> <p>I just smiled.</p> <p>Only a few days later I caught up why he was basically wrong.</p> <p>No, I am not going to say that we find good bugs.</p> <p>I am going to say that</p> <div class="center"> <b>WE DO NOT SEARCH FOR BUGS AT ALL.</b> </div> <p><br /></p> <h3 id="what-is-quality-assurance">What is Quality Assurance</h3> <p>This is very, very important. Every QA engineer should know it from the childhood.</p> <p>QA means “Quality Assurance”. It means “being sure that software works”. Our first job is not to <u>find all bugs</u>. Our first job is to be sure that <u>software does its job</u>.</p> <h3 id="for-example">For example</h3> <p>If we develop an internet-shop for selling TVs, the job of QA is to assure that user can find TV, press the big “Buy” button and pay money. This is the most important job.</p> <p>Maybe banner looks bad. Maybe “Print PDF” button opens a new empty window. May be the “login” disappears sometimes. Surely, these are errors, but these are secondary errors. Surely, it’s bad if you have such errors, but the business still <em>will work</em>. But if the “Buy” button is not clickable - it’s the end of the business. User cannot pay his money. It’s a big difference!</p> <p>And there are a plenty of thirdly errors - when user enters 1000 chinese characters into “login” field and gets 500 error. No one normal user will do that. And if he does, let him get this 500 error.</p> <p>I am not saying that these secondary and thirdly errors should not be searched and fixed. Sure, You should find and fix them. But only when you are sure that <em>the business works</em>.</p> <p>So,</p> <h3 id="the-main-conclusion">the main conclusion:</h3> <ol> <li>Your <strong>first test</strong> should be “<strong>green path</strong>”. A typical scenario that bring the money:<br /> Find TV - “Buy” - pay. Whatever you do: write automated tests or test manually. Your first test - green path.</li> </ol> <p>This approach has one psychological disadvantage. This is the most boring test. This is a guarantee to find less bugs than your colleagues. This is a guarantee to make your boss feeling that you are not doing anything useful. But this is still the most important job of QA department.</p> <ol> <li>All these <strong>stupid tests</strong> about “<strong>1000 chinese characters</strong> in the login field” - you can do them, but only if all other things are ok. And you have free time that you cannot spend to anything else. In practice, that means - never.</li> </ol> <p>But this is exactly the sort of bugs that QA engineers do generate during every release. Again and again. These meaningless bug reports waste your time, waste your resources, waste your attention, thus letting the real bugs appear unnoticed.</p> <p>But this is a guarantee to find 50 new bugs at every release. This is a guarantee to get a top employee of the month. It’s call “local optimization”, and this is the most powerful of devil’s inventions.</p> <p>Do not run chase for bugs. You cannot catch all bugs in the world. It’s like pimple: you squeeze one - three more will appear. You don’t need to watch the pimples - you need to monitor the overall health. Do sport, do healthy eating, do hygiene - and pimples will disappear automatically. Do write the most important tests first. Make them fast. Make them stable. It’s better to have tests green (and you will feel alarm when then get red once) than having a lot of tests red (and nobody will catch sight of the real problem).</p> <p>That’s because I am saying:</p> <h3 id="we-do-not-search-for-bugs">We do not search for bugs</h3> <p>We assure that software works. We write automated test to assure that user can buy TV. It allows us to avoid wasting time for maintaining plenty of meaningless bug reports and useless tests. It frees up our resources for quickly reacting to real problems that will always appear in production, not depending on QA department existence. It allows us to develop and maintain a complicated software with a small team. Small, but very effective team.</p> <p><em>In testo veritas!</em></p> <p><br /></p> https://selenide.org/2014/12/09/you-find-wrong-bugs/ https://selenide.org/2014/12/09/you-find-wrong-bugs 2014-12-09T00:00:00+00:00 Changes in Selenide 2.15 <p>Good evening!</p> <p>Good news: we have released Selenide 2.15. This time we have a lot of new features.</p> <h3 id="sizzle-selectors-css3">Sizzle selectors (CSS3)</h3> <p>Now you can use <a href="http://sizzlejs.com/">CSS3 selectors</a> in Selenide for searching web elements!</p> <p>For example:</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">":contains('Tere Martin!')"</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="s">":not(a#id)"</span><span class="o">);</span> <span class="err">$$</span><span class="o">(</span><span class="s">":not(div,p)"</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> <span class="err">$</span><span class="o">(</span><span class="s">"[value!='johnny']"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"div:has(span)"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">":input"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">":text"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">":checkbox"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">":file"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">":password"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">":image"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">":header"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">":first"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">":last"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">":even"</span><span class="o">);</span> </code></pre></div></div> <p>To enable Sizzle selectors, add this line to your 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">selectorMode</span> <span class="o">=</span> <span class="nc">Sizzle</span><span class="o">;</span> </code></pre></div></div> <p>Feel free to share your experience with us. Did it work for you?</p> <h3 id="multifile-upload">Multifile upload</h3> <p>Now functions <code class="language-plaintext highlighter-rouge">$.uploadFile()</code> and <code class="language-plaintext highlighter-rouge">$.uploadFileFromClasspath()</code> can accept multiple arguments. This means that you can upload multiple files with Selenide!</p> <p>Standard Selenium webdriver doesn’t provide such function, so we had to make it with a help of black magic. Please share your experience, if it worked for you.</p> <h3 id="support-for-browsermob-proxy">Support for BrowserMob proxy</h3> <p>We added convenient way for Selenide to add Proxy server to webdriver. First of all, it was needed for <a href="http://bmp.lightbody.net/">BrowserMob proxy</a> - a popular tool among testers. It allows to intercept http requests between web application and browser, thus making possible many things that are now allowed with pure Selenium webdriver:</p> <ul> <li>file download from server,</li> <li>authorization on site,</li> <li>asserting HTTP statuses,</li> <li>and so on</li> </ul> <blockquote> <p>Thanks to <a href="https://github.com/proton72">Vladimir Denisov</a> for this pull request!</p> </blockquote> <p>Here is an example of using BrowserMob Proxy with Selenide <a href="https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/proxy/ProxyServerUsageTest.java">ProxyServerUsageTest.java</a>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">ProxyServer</span> <span class="n">proxyServer</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ProxyServer</span><span class="o">(</span><span class="n">findFreePort</span><span class="o">());</span> <span class="n">proxyServer</span><span class="o">.</span><span class="na">start</span><span class="o">();</span> <span class="n">proxyServer</span><span class="o">.</span><span class="na">newHar</span><span class="o">(</span><span class="s">"google-test"</span><span class="o">);</span> <span class="nc">WebDriverRunner</span><span class="o">.</span><span class="na">setProxy</span><span class="o">(</span><span class="n">proxyServer</span><span class="o">.</span><span class="na">seleniumProxy</span><span class="o">());</span> <span class="n">open</span><span class="o">(</span><span class="s">"http://google.com"</span><span class="o">);</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">HarEntry</span><span class="o">&gt;</span> <span class="n">harEntries</span> <span class="o">=</span> <span class="n">proxyServer</span><span class="o">.</span><span class="na">getHar</span><span class="o">().</span><span class="na">getLog</span><span class="o">().</span><span class="na">getEntries</span><span class="o">();</span> <span class="n">assertTrue</span><span class="o">(</span><span class="n">harEntries</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">getRequest</span><span class="o">().</span><span class="na">getUrl</span><span class="o">().</span><span class="na">equals</span><span class="o">(</span><span class="s">"http://google.com"</span><span class="o">));</span> </code></pre></div></div> <p><br /></p> <h3 id="you-can-zoom-page-now">You can zoom page now!</h3> <p>You can find sample usage <a href="https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/SelenideMethodsTest.java#LC504">in tests</a>:</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="n">zoom</span><span class="o">(</span><span class="mf">2.0</span><span class="o">);</span> <span class="c1">// Enlarge page zoom twice</span> <span class="n">zoom</span><span class="o">(</span><span class="mf">0.5</span><span class="o">);</span> <span class="c1">// Zoom out twice</span> </code></pre></div></div> <p>It can be useful for testing responsive design.</p> <h3 id="support-for-json-and-ical">Support for JSON and iCal</h3> <p>You can now open non-html pages with Selenide.</p> <p>It can be useful for testing json, iCal etc. resources. Sometimes it’s useful to check them inside UI tests.</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="n">source</span><span class="o">(),</span> <span class="n">containsString</span><span class="o">(</span><span class="s">"DTSTART:20140409T090000"</span><span class="o">));</span> </code></pre></div></div> <h3 id="support-for-tabs-and-windowstabs">Support for tabs and windows/tabs</h3> <p>Now Selenide allows switching between tabs/windows/frames not only by title, but also by index (0, 1, 2, …).</p> <p>Examples of <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/FramesTest.java">switching between frames</a>:</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="mi">0</span><span class="o">);</span> <span class="n">assertTrue</span><span class="o">(</span><span class="n">source</span><span class="o">().</span><span class="na">contains</span><span class="o">(</span><span class="s">"Hello, WinRar!"</span><span class="o">));</span> <span class="n">switchTo</span><span class="o">().</span><span class="na">defaultContent</span><span class="o">();</span> <span class="n">switchTo</span><span class="o">().</span><span class="na">frame</span><span class="o">(</span><span class="mi">1</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">"Page with dynamic select"</span><span class="o">));</span> </code></pre></div></div> <p>Examples of <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/TabsTest.java">switching between tabs</a>:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">switchToWindow</span><span class="o">(</span><span class="mi">1</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">"Page with JQuery"</span><span class="o">));</span> <span class="n">switchToWindow</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">"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">"File uploads"</span><span class="o">));</span> <span class="n">switchToWindow</span><span class="o">(</span><span class="mi">3</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">"Page with alerts"</span><span class="o">));</span> <span class="n">switchToWindow</span><span class="o">(</span><span class="mi">0</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">"Tabs"</span><span class="o">));</span> </code></pre></div></div> <h3 id="support-for-allure-framework">Support for Allure Framework</h3> <p>We have added function to get screenshot as a file:</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">Screenshots</span><span class="o">.</span><span class="na">getScreenShotAsFile</span><span class="o">;</span> <span class="nc">File</span> <span class="n">screenshot</span> <span class="o">=</span> <span class="n">getScreenShotAsFile</span><span class="o">();</span> </code></pre></div></div> <p>It can be used for integration with <a href="http://allure.qatools.ru/">Allure Framework</a>.</p> <blockquote> <p>Thanks to <a href="https://github.com/proton72">Vladimir Denisov</a> for this pull request!</p> </blockquote> <h3 id="upgraded-to-selenium-2440">Upgraded to <a href="https://raw.githubusercontent.com/SeleniumHQ/selenium/master/java/CHANGELOG">Selenium 2.44.0</a>.</h3> <ul> <li>Note that it brings upgrade of Google Guava to version 18.0.</li> <li>Unfortunately, PhantomJS 1.2 does not work with Selenium webdriver 2.44.0 :( We have already committed <a href="https://github.com/detro/ghostdriver/pull/399">Pull Request to ghostdriver</a> for ghostdriver. Now waiting until it gets released.</li> </ul> <p><br /></p> <p>And what’s up with you?</p> <p><br /></p> https://selenide.org/2014/11/03/selenide-2.15/ https://selenide.org/2014/11/03/selenide-2.15 2014-11-03T00:00:00+00:00 How to start writing UI tests in 10 minutes <p>Hi!</p> <p>People often ask: how to learn writing tests? How to start? How to write first test in Selenium?</p> <p>Now we have an answer!</p> <p>This video tutorial demonstrates how to create a project with Maven and write a test that opens a Google in browser, enters a word and checks for search results.</p> <center> <iframe src="//player.vimeo.com/video/107647158" width="800" height="450" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe> <p><a href="https://vimeo.com/107647158">How to start writing UI tests in 10 minutes</a> from <a href="https://vimeo.com/user20427140">Selenide</a> on <a href="https://vimeo.com">Vimeo</a>.</p> <p>Selenide tutorial</p> </center> <p>Please feel free to <a href="/contacts.html">give your feedback</a>!</p> <p><br /></p> https://selenide.org/2014/10/01/how-to-start-writing-ui-tests/ https://selenide.org/2014/10/01/how-to-start-writing-ui-tests 2014-10-01T00:00:00+00:00 Changes in 2.13 and 2.14 <p>Hi Seleniders!</p> <p>In September we released two versions of Selenide: 2.13 and 2.14. There is not so much new functions, but there is one new function that I want to discuss with you. Let’s start with it.<br /> <br /></p> <h3 id="fast-method-setvalue">Fast method $.setValue</h3> <p>In Codeborne we analyzed performance of tests in few real projects and discovered that the most slow part of tests is filling text fields (not XPath search as many of us think). In other words, method <code class="language-plaintext highlighter-rouge">$.setValue</code> (or <code class="language-plaintext highlighter-rouge">WebElement.sendKeys</code>) is the bottleneck. It’s because Selenium emulates keypress of every single key with all related events: keyDown, keyUp etc. - thus making method <code class="language-plaintext highlighter-rouge">sendKeys</code> quite slow. <br /> <br /></p> <p>It’s possible to disable generating events, but in this case some functionality will be broken that uses these events: autocompletion, autosuggestions etc. <br /> <br /></p> <p>We have found a solution. Let’s Selenide have two separate methods: <code class="language-plaintext highlighter-rouge">$.sendKeys</code> and <code class="language-plaintext highlighter-rouge">$.setValue</code>. The first one will work like Selenium by default: slowly and with generating events. The second one will be fast, setting values to text fields using JavaScript. So test author can decide in which case which method is needed. In most cases the fast method <code class="language-plaintext highlighter-rouge">$.setValue</code> can be used, because there is not so much autocompletions comparing to “regular” text fields. <br /> <br /></p> <p>In our projects using of fast <code class="language-plaintext highlighter-rouge">$.setValue</code> method gave 10% of performance improvement. <br /> <br /></p> <p>NB! This is experimental feature. It can be enabled by flag <code class="language-plaintext highlighter-rouge">-Dselenide.fastSetValue=true</code>. By default it’s disabled, thus <code class="language-plaintext highlighter-rouge">$.setValue</code> works exactly the same as <code class="language-plaintext highlighter-rouge">$.sendKeys</code>. <br /> <br /></p> <h3 id="added-method-for-checking-images-imgisimage">Added method for checking images <code class="language-plaintext highlighter-rouge">$("img").isImage()</code></h3> <p>Method <code class="language-plaintext highlighter-rouge">$("img").isImage()</code> returns <code class="language-plaintext highlighter-rouge">true</code> if the image has been correctly loaded. The method can be used only for <code class="language-plaintext highlighter-rouge">&lt;img&gt;</code> elements.</p> <p>An example of usage can be found in test <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/ImageTest.java">ImageTest</a>.</p> <p>NB! The functions does not work in HtmlUnit.</p> <h3 id="added-possibility-to-add-descriptions-to-asserts-like-in-junit-and-testng-asserts">Added possibility to add descriptions to asserts (like in JUnit and TestNG asserts)</h3> <p>Now you can add a custom message to all should-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">"#kpp"</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="s">"Private customers cannot have KPP"</span><span class="o">,</span> <span class="n">empty</span><span class="o">);</span> </code></pre></div></div> <p>In case of test failure this description will be added to 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">should</span> <span class="n">be</span> <span class="n">empty</span> <span class="o">{</span><span class="nc">By</span><span class="o">.</span><span class="na">id</span><span class="o">:</span> <span class="n">kpp</span><span class="o">}</span> <span class="n">because</span> <span class="nc">Private</span> <span class="n">customers</span> <span class="n">cannot</span> <span class="n">have</span> <span class="no">KPP</span> <span class="nl">Element:</span> <span class="err">'</span><span class="o">&lt;</span><span class="n">input</span> <span class="n">id</span><span class="o">=</span><span class="s">"kpp"</span><span class="o">&gt;</span><span class="mo">012</span><span class="mi">973891263</span><span class="o">&lt;/</span><span class="n">input</span><span class="o">&gt;</span><span class="err">'</span> <span class="nl">Screenshot:</span> <span class="nl">file:</span><span class="o">/</span><span class="nc">Users</span><span class="o">/</span><span class="n">andrei</span><span class="o">/</span><span class="n">projects</span><span class="o">/</span><span class="n">selenide</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">integration</span><span class="o">/</span><span class="nc">SelenideMethodsTest</span><span class="o">/</span><span class="n">waitUntilMethodMayContainOptionalMessageThatIsPartOfErrorMessage</span><span class="o">/</span><span class="mf">1411898416054.0</span><span class="o">.</span><span class="na">png</span> <span class="nl">Timeout:</span> <span class="mi">4</span> <span class="n">s</span><span class="o">.</span> </code></pre></div></div> <p>I am not sure that this feature is designed in the most convenient way. So, I am waiting for your suggestions. How could it be made more easy to use?</p> <p>Maybe this API would be more convenient?</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">"#kpp"</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">empty</span><span class="o">.</span><span class="na">because</span><span class="o">(</span><span class="s">"Private customers cannot have KPP"</span><span class="o">));</span> </code></pre></div></div> <p>But in this case you will need to duplicate the description if you want to check multiple conditions in a line.</p> <p>One more 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">"#kpp"</span><span class="o">).</span><span class="na">because</span><span class="o">(</span><span class="s">"Private customers cannot have KPP"</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">empty</span><span class="o">);</span> </code></pre></div></div> <p>And finally, the “because” word is doubtful: in different situations you may find more appropriate to use other words.</p> <p>What do you think?</p> <h3 id="added-wrappers-be-and-have">Added wrappers <code class="language-plaintext highlighter-rouge">be</code> and <code class="language-plaintext highlighter-rouge">have</code>.</h3> <p>Now you have alternative way to write checks:</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">should</span><span class="o">(</span><span class="n">have</span><span class="o">(</span><span class="n">text</span><span class="o">(</span><span class="s">"Ivan"</span><span class="o">)));</span> <span class="err">$</span><span class="o">(</span><span class="s">"br"</span><span class="o">).</span><span class="na">should</span><span class="o">(</span><span class="n">be</span><span class="o">(</span><span class="n">empty</span><span class="o">));</span> </code></pre></div></div> <p>It may be useful when using Selenide with frameworks like EasyB that also use terms <code class="language-plaintext highlighter-rouge">shouldBe</code> or <code class="language-plaintext highlighter-rouge">shouldHave</code> for their needs.</p> <p><br /></p> <h3 id="upgraded-to-selenium-2431">Upgraded to <a href="https://raw.githubusercontent.com/SeleniumHQ/selenium/master/java/CHANGELOG">Selenium 2.43.1</a>.</h3> <p>Many testers have been waiting for this upgrade for a while. First of all, because of FireFox 32 support. And also because of new InternetExplorer driver.</p> <p>We have not encountered any problems with the new Selenium 2.43.1.</p> <p><br /></p> <p>And what’s up with you?</p> <p><br /></p> https://selenide.org/2014/09/28/selenide-2.13-and-2.14/ https://selenide.org/2014/09/28/selenide-2.13-and-2.14 2014-09-28T00:00:00+00:00 Selenide usage simple notes: IE, TestNG, Bootstrap dropdown <p>Hello!</p> <p>My name is Sergey Shimkiv. Below you can find some notes about Selenide/Selenium usage. <br /> <br /></p> <h3 id="ie-notes">IE notes</h3> <p>IE 11 x32/x64. In some cases after the actions with HTML elements (<code class="language-plaintext highlighter-rouge">click()</code> for example) you can receive an exception. <br /> The cause of it could be synthetic events usage. The workaround is to use native events for IE:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">capabilities</span><span class="o">.</span><span class="na">setCapability</span><span class="o">(</span><span class="s">"nativeEvents"</span><span class="o">,</span> <span class="s">"true"</span><span class="o">);</span> </code></pre></div></div> <p>https://code.google.com/p/selenium/wiki/InternetExplorerDriver <br /></p> <h3 id="one-way-to-add-selenide-screenshot-into-the-testng-html-reporter">One way to add Selenide screenshot into the TestNG HTML reporter</h3> <p>In some cases you might want to add Selenide’s screenshots of failed tests into your TestNG HTML reporter.</p> <p>For example: You write two tests (Test1 and Test2) which must be linked (Test2 depends on Test1 results). But you know that Test1 will fail because of application bug(s). So you will write something like this:</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="kd">public</span> <span class="kt">void</span> <span class="nf">Test1</span><span class="o">()</span> <span class="o">{</span> <span class="o">...</span> <span class="k">try</span> <span class="o">{</span> <span class="c1">// Test block with known bug</span> <span class="o">}</span> <span class="k">catch</span><span class="o">(...)</span> <span class="o">{</span> <span class="c1">// Some actions</span> <span class="o">}</span> <span class="k">finally</span> <span class="o">{</span> <span class="c1">// You want to perform some actions here to ensure correct preconditions for the Test2</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div></div> <p>Let’s assume that you’re using own test listener that extends <code class="language-plaintext highlighter-rouge">TestListenerAdapter</code>. And you have overridden <code class="language-plaintext highlighter-rouge">onTestFailure(ITestResult result)</code> method to collect some additional information into the HTML report - your own screenshots for example. In such case it is possible that your screenshot gathering implementation will collect incorrect data because <code class="language-plaintext highlighter-rouge">finally</code> block can be performed before screenshot will be taken.</p> <p>Just keep in mind that Selenide’s screenshot file name (that will be taken directly after some exception) could be taken from <code class="language-plaintext highlighter-rouge">result.getThrowable().getMessage();</code> <br /></p> <h3 id="one-way-to-work-with-customized-bootstrap-html-elements">One way to work with customized Bootstrap HTML elements</h3> <p>Tests often get complicated when you need to test customized HTML controls with complex logic.</p> <p>For example, Bootstrap’s dropdown elements are represented via set of HTML elements. In common:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"dropdown"</span><span class="nt">&gt;</span> <span class="nt">&lt;button</span> <span class="na">class=</span><span class="s">"btn btn-default dropdown-toggle"</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">id=</span><span class="s">"dropdownMenu1"</span> <span class="na">data-toggle=</span><span class="s">"dropdown"</span><span class="nt">&gt;</span> Dropdown <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"caret"</span><span class="nt">&gt;&lt;/span&gt;</span> <span class="nt">&lt;/button&gt;</span> <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"dropdown-menu"</span> <span class="na">role=</span><span class="s">"menu"</span> <span class="na">aria-labelledby=</span><span class="s">"dropdownMenu1"</span><span class="nt">&gt;</span> <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span><span class="nt">&gt;&lt;a</span> <span class="na">role=</span><span class="s">"menuitem"</span> <span class="na">tabindex=</span><span class="s">"-1"</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Action<span class="nt">&lt;/a&gt;&lt;/li&gt;</span> <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span><span class="nt">&gt;&lt;a</span> <span class="na">role=</span><span class="s">"menuitem"</span> <span class="na">tabindex=</span><span class="s">"-1"</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Another action<span class="nt">&lt;/a&gt;&lt;/li&gt;</span> <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span><span class="nt">&gt;&lt;a</span> <span class="na">role=</span><span class="s">"menuitem"</span> <span class="na">tabindex=</span><span class="s">"-1"</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Something else here<span class="nt">&lt;/a&gt;&lt;/li&gt;</span> <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span> <span class="na">class=</span><span class="s">"divider"</span><span class="nt">&gt;&lt;/li&gt;</span> <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span><span class="nt">&gt;&lt;a</span> <span class="na">role=</span><span class="s">"menuitem"</span> <span class="na">tabindex=</span><span class="s">"-1"</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Separated link<span class="nt">&lt;/a&gt;&lt;/li&gt;</span> <span class="nt">&lt;/ul&gt;</span> <span class="nt">&lt;/div&gt;</span> </code></pre></div></div> <p>The problem is that the <code class="language-plaintext highlighter-rouge">&lt;ul&gt;</code> element initially is not visible for the Selenium (and for Selenide too). To be able to select some dropdown element value you can:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">SelenideElement</span> <span class="n">parentDiv</span> <span class="o">=</span> <span class="err">$</span><span class="o">(</span><span class="s">".dropdown"</span><span class="o">);</span> <span class="c1">// Find `&lt;button&gt;` element and `click()` on it</span> <span class="n">parentDiv</span><span class="o">.</span><span class="na">find</span><span class="o">(</span><span class="s">"button"</span><span class="o">).</span><span class="na">scrollTo</span><span class="o">().</span><span class="na">click</span><span class="o">();</span> <span class="c1">// Now you can find needed dropdown element value by text</span> <span class="n">parentDiv</span><span class="o">.</span><span class="na">find</span><span class="o">(</span><span class="s">".dropdown-menu"</span><span class="o">).</span><span class="na">find</span><span class="o">(</span><span class="n">withText</span><span class="o">(</span><span class="s">"Action"</span><span class="o">)).</span><span class="na">parent</span><span class="o">().</span><span class="na">click</span><span class="o">();</span> </code></pre></div></div> <p><br /> In the next post I would like to share experience in the automated testing environment deployment (based on Grid2). <br /><br /> Thanks to the Selenide’s authors for their great tool ;) <br /> <br /></p> <p>Sergey Shimkiv <br /></p> https://selenide.org/2014/08/25/selenide-usage-notes/ https://selenide.org/2014/08/25/selenide-usage-notes 2014-08-25T00:00:00+00:00 Shorten your code <p>Hi all!</p> <p>This is <em>Prezi</em> presentation about Selenide from <a href="http://prezi.com/user/-yv8ll42j1_i/">Ashwin Dalvi</a>.</p> <p><br /> <br /></p> <h3 id="pros-cons-and-myths">Pros, Cons and Myths:</h3> <iframe src="http://prezi.com/embed/d18jggopjyaj/?bgcolor=ffffff&amp;lock_to_path=0&amp;autoplay=0&amp;autohide_ctrls=0&amp;features=undefined&amp;disabled_features=undefined&amp;html5=1" width="800" height="600" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe> <p><br /> Selenide: Shorten your code!</p> <p><br /></p> https://selenide.org/2014/08/08/shorten-your-code/ https://selenide.org/2014/08/08/shorten-your-code 2014-08-08T00:00:00+00:00 Changes in Selenide 2.12 <p>Hello QA geeks!</p> <p>Great news: we have released Selenide 2.12. Let’s see what’s coming with it. <br /> <br /></p> <h3 id="added-function-uploadfilefile">Added function $.uploadFile(File)</h3> <p>The function allows you to upload a file.</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">File</span> <span class="n">cv</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">File</span><span class="o">(</span><span class="s">"src/test/resources/cv.pdf"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#cvFileUpload"</span><span class="o">).</span><span class="na">uploadFile</span><span class="o">(</span><span class="n">cv</span><span class="o">);</span> </code></pre></div></div> <p>Selenide already had a similar function <code class="language-plaintext highlighter-rouge">$.uploadFromClasspath(String fileName)</code>. It searched the file for uploading in classpath. We believe that holding test file together with test sources is a good practice (meaning that test files get to classpath during project compilation).</p> <p>But we realized that sometimes it’s convenient to upload some file from another place.</p> <p><br /></p> <h3 id="fixed-function-uploadfromclasspath">Fixed function $.uploadFromClasspath</h3> <p>It appeared that webdriver fails when trying to upload a file like <code class="language-plaintext highlighter-rouge">c:/src/test/java/../resources/cv.pdf</code>. We improved function <code class="language-plaintext highlighter-rouge">$.uploadFromClasspath</code>, so that it removes extra “..” parts from file name.</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">"#cvFileUpload"</span><span class="o">).</span><span class="na">uploadFromClasspath</span><span class="o">(</span><span class="s">"cv.pdf"</span><span class="o">);</span> </code></pre></div></div> <p><br /></p> <h3 id="function-valjohn-also-works-for-selects">Function $.val(“john”) also works for selects</h3> <p>Function <code class="language-plaintext highlighter-rouge">$.val</code> has got a little bit smarter. It called on <code class="language-plaintext highlighter-rouge">SELECT</code> field, it chooses the right <code class="language-plaintext highlighter-rouge">OPTION</code> with corresponding <code class="language-plaintext highlighter-rouge">value</code>. This is one more step towards the idea that developer doesn’t need to think about implementation details and can concentrate on business logic. You just write <code class="language-plaintext highlighter-rouge">$("#sex").val("female")</code> and don’t think either it’s <code class="language-plaintext highlighter-rouge">INPUT</code> or <code class="language-plaintext highlighter-rouge">SELECT</code> - Selenide detects it automatically and performs required action.</p> <p>Technically, <code class="language-plaintext highlighter-rouge">$("select").val("yes")</code> - is a synonym for <code class="language-plaintext highlighter-rouge">$("select").selectOptionByValue("yes")</code>.</p> <p><br /></p> <h3 id="added-function-getwebdriverlogs">Added function <code class="language-plaintext highlighter-rouge">getWebDriverLogs()</code>.</h3> <p>The function reads webdriver logs. Technically it’s synonym for <code class="language-plaintext highlighter-rouge">webdriver.manager().logs()</code>. In theory, these logs can contain very useful information about browser errors, javascript errors, performance problems etc. In practice, webdriver logs are not well supported by all webdrivers. We do not understand how to use them efficiently. Please share with us if you have any experience with webdriver logs!</p> <p><br /></p> <h3 id="upgraded-to-selenium-2422-and-htmlunit-215">Upgraded to <a href="https://raw.githubusercontent.com/SeleniumHQ/selenium/master/java/CHANGELOG">Selenium 2.42.2</a> and <a href="http://htmlunit.sourceforge.net/changes-report.html#a2.15">HtmlUnit 2.15</a></h3> <p>We haven’t experienced any problems with the new Selenium.</p> <p>Thanks again to Selenium authors for the great product!</p> <p><br /></p> <p>And what’s new with you?</p> <p><br /></p> https://selenide.org/2014/07/05/selenide-2.12/ https://selenide.org/2014/07/05/selenide-2.12 2014-07-05T00:00:00+00:00 Changes in Selenide 2.11 <p>Hello!</p> <p>We have released Selenide 2.11. It does contains no new features, but removes old unused features, that made our life complex and broke down the progress. <br /> <br /></p> <p>Please be so nice and run your tests with Selenide 2.11. Notify us if some tests got broken. <br /> <br /></p> <h2 id="what-we-cleaned-up">What we cleaned up</h2> <h3 id="removed-dependency-on-jquery">Removed dependency on jQuery</h3> <p>Methods $.selectOption() and $.selectOptionByValue() tried to trigger “change” event using jQuery. It was done a long time ago to fight against some odd test failures on Windows in IE. Now it’s actual anymore</p> <ul> <li>at least all our tests are passing without this hack. <br /> <br /></li> </ul> <p>The whole class <code class="language-plaintext highlighter-rouge">com.codeborne.selenide.JQuery</code> is marked as <code class="language-plaintext highlighter-rouge">deprecated</code>. Please be sure that you do not use it in your tests.</p> <p><br /></p> <h3 id="cleaned-up-annoying-logs">Cleaned up annoying logs</h3> <p>When closing Firefox, you could see the following annoying error message in log:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">“</span><span class="nl">UnreachableBrowserException:</span> <span class="nc">Error</span> <span class="n">communicating</span> <span class="n">with</span> <span class="n">the</span> <span class="n">remote</span> <span class="n">browser</span><span class="o">.</span> <span class="nc">It</span> <span class="n">may</span> <span class="n">have</span> <span class="n">died</span><span class="o">.</span><span class="err">”</span> </code></pre></div></div> <p><br /> <br /></p> <p>We researched this problem and found that this is a bug (or feature?) of Selenium Firefox webdriver. When calling method <code class="language-plaintext highlighter-rouge">webdriver.close()</code> it throws <code class="language-plaintext highlighter-rouge">UnreachableBrowserException</code>, but still closes the browser (at least, in Linux and Mac OS). <br /> <br /></p> <p>We removed this pointless log. <br /> <br /></p> <h2 id="and-what-we-updated">And what we updated</h2> <h3 id="upgraded-to-phantomjs-120">Upgraded to PhantomJS 1.2.0</h3> <p>As before, all tests of Selenide itself run successfully in PhantomJS, but some tests in our real projects fail. That’s why we still cannot use PhantomJS in real work.</p> <p><br /></p> <p>And what’s new with you?</p> <p><br /></p> https://selenide.org/2014/05/23/selenide-2.11/ https://selenide.org/2014/05/23/selenide-2.11 2014-05-23T00:00:00+00:00 Changes in Selenide 2.10 <p>Hi all!</p> <p>Recently we released Selenide 2.10. Let me introduce you the news!</p> <h2 id="new-functions">New functions</h2> <h3 id="working-with-windowstabs">Working with windows/tabs</h3> <p>Selenium WebDriver does not support convenient API for working with windows and tabs. It only suggests method <code class="language-plaintext highlighter-rouge">getWindowHandles()</code> that returns set of strings - identifiers of opened windows. It’s not trivial to find the needed one from these handles. <br /> <br /> As Selenide primary goal is to free developer’s head from browser technical details, we want to make working with windows/tabs easy and intuitive. We started this movement from a simple thing: we have added method</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">switchToWindow</span><span class="o">(</span><span class="nc">String</span> <span class="n">title</span><span class="o">)</span> </code></pre></div></div> <p>You can find a sample usage <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/TabsTest.java#LC45">in Selenide tests</a>:</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">canSwitchToWindowByTitle</span><span class="o">()</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">"Page2: alerts"</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">byText</span><span class="o">(</span><span class="s">"Page1: uploads"</span><span class="o">)).</span><span class="na">click</span><span class="o">();</span> <span class="n">switchToWindow</span><span class="o">(</span><span class="s">"Test::alerts"</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">"Page with alerts"</span><span class="o">));</span> <span class="n">switchToWindow</span><span class="o">(</span><span class="s">"Test::uploads"</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">"File uploads"</span><span class="o">));</span> <span class="o">}</span> </code></pre></div></div> <p>We are planning to continue working on simplifying windows/tabs API - probably with help of new Java 8 features.</p> <p>How would you like to use windows? Please feel free to share your ideas! <br /> <br /></p> <h3 id="new-methods-hover-and-draganddroptotarget">New methods <code class="language-plaintext highlighter-rouge">$.hover()</code> and <code class="language-plaintext highlighter-rouge">$.dragAndDropTo(target)</code></h3> <p><br /> Method <code class="language-plaintext highlighter-rouge">$.hover()</code> emulates moving mouse over the element (without clicking). Find example <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/HoverTest.java">here</a>. <br /> <br /> Method <code class="language-plaintext highlighter-rouge">$.dragAndDropTo(target)</code> can drag an element and drop into another element. Example:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">$</span><span class="o">(</span><span class="s">"#from"</span><span class="o">).</span><span class="na">dragAndDropTo</span><span class="o">(</span><span class="s">"#to"</span><span class="o">)</span> </code></pre></div></div> <p><br /></p> <h3 id="new-methods-for-searching-parentancestors-parent-and-closest">New methods for searching parent/ancestors <code class="language-plaintext highlighter-rouge">$.parent()</code> and <code class="language-plaintext highlighter-rouge">$.closest()</code></h3> <p>I often need to get a parent element. Or even ancestor, not direct parent. For example, I often search a DIV by text - this DIV is located inside a table. Then I want to find the table row containing the DIV. The only way to find it was using XPATH. <br /> <br /> Now you can use convenient <code class="language-plaintext highlighter-rouge">$.parent()</code> or <code class="language-plaintext highlighter-rouge">$.closest()</code> 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="n">byText</span><span class="o">(</span><span class="s">"Row 1"</span><span class="o">)).</span><span class="na">parent</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">"Row 2"</span><span class="o">)).</span><span class="na">closest</span><span class="o">(</span><span class="s">"tr"</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">"firstName"</span><span class="o">)).</span><span class="na">closest</span><span class="o">(</span><span class="s">".form"</span><span class="o">);</span> </code></pre></div></div> <p>You can find more examples <a href="https://github.com/selenide/selenide/blob/master/src/test/java/integration/ParentTest.java">here</a> <br /> <br /></p> <h3 id="tracing-javascript-errors">Tracing JavaScript errors</h3> <p>Now Selenide tries to automatically catch all JavaScript errors that happened on a page. <br /> <br /> What we do we them? <br /> <br /> First of all, Selenide automatically <strong>adds JS errors to the error message</strong> when your test fails. Basically, it’s sufficient. If you want more control, you can use the following methods:</p> <ul> <li><code class="language-plaintext highlighter-rouge">Selenide.getJavascriptErrors()</code> - returns all JavaScript errors on current page.</li> <li><code class="language-plaintext highlighter-rouge">Selenide.assertNoJavascriptErrors()</code> - fails the test if there have been some JavaScript errors on current page.</li> </ul> <p><br /> P.S. By now it’s implemented very simply (using the <code class="language-plaintext highlighter-rouge">window.onerror</code> function). I am not sure it works pretty well in all browsers. And it cannot catch all errors. So, feel free to share you ideas how to implement it better.</p> <p><br /></p> <h2 id="bugfixes-and-improvements">Bugfixes and improvements</h2> <h3 id="closing-webdrivers">Closing webdrivers</h3> <p>Mechanism of automatic closing webdrivers was improved for case when one of webdrivers is hanging (and thus cannot be closed and prevents closing of other webdrivers). Thanks to Aleksander Gavrilenko for this nontrivial fix!</p> <h3 id="selenide-does-not-wait-for-body">Selenide does not wait for &lt;body&gt;</h3> <p>Method <code class="language-plaintext highlighter-rouge">open(url)</code> doesn’t wait until the tag &lt;body&gt; appears in the document. This is just an old code that is not needed since Selenide automatically waits for required conditions.</p> <h3 id="upgrade-to-selenium-2410">Upgrade to Selenium 2.41.0</h3> <p>As usually, we upgraded to latest Selenium WebDriver version.</p> <p>We haven’t observed any problems with the new Selenium. It works.</p> <h2 id="other-news">Other news</h2> <p>March statistics of Selenide downloads is just great!</p> <p>We became twice as much during one month! Wow!</p> <center> <img src="/images/2014/04/selenide_downloads.2014-03.png" width="800" /> </center> <p><br /></p> <p>And what’s new with you?</p> <p><br /></p> https://selenide.org/2014/04/27/selenide-2.10/ https://selenide.org/2014/04/27/selenide-2.10 2014-04-27T00:00:00+00:00 Changes in Selenide 2.9 <p>Good evening!</p> <p>Today was released Selenide 2.9. Let me tell you about the changes in the new version.</p> <h2 id="new-functionality">New functionality</h2> <h3 id="added-support-for-safari-browser">Added support for Safari browser</h3> <p>Indeed, Safari driver doesn’t seem to be stable yet. At least, some Selenide tests still fail on Safari.</p> <p>Another problem with Safari is that it doesn’t support JS alerts and cannot open local files like <code class="language-plaintext highlighter-rouge">file://c:/tmp.txt</code>.</p> <p>Please feel free to share your experience with Safari webdriver!</p> <h3 id="added-condition-or">Added condition <code class="language-plaintext highlighter-rouge">or</code></h3> <p>Now you can declare composite conditions like this:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">Condition</span> <span class="n">completed</span> <span class="o">=</span> <span class="n">or</span><span class="o">(</span><span class="s">"completed"</span><span class="o">,</span> <span class="n">started</span><span class="o">,</span> <span class="n">inProgress</span><span class="o">,</span> <span class="n">loading</span><span class="o">);</span> </code></pre></div></div> <p>and use them in your tests:</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#page"</span><span class="o">).</span><span class="na">shouldBe</span><span class="o">(</span><span class="n">completed</span><span class="o">);</span> </code></pre></div></div> <p>Actually I am not sure it’s a good idea. I believe that test should always know exactly, in which state the element should be at any moment. But folks insisted that <code class="language-plaintext highlighter-rouge">or</code> condition can be useful.</p> <h3 id="added-method-screenshootertofolder">Added method <code class="language-plaintext highlighter-rouge">ScreenShooter.to(folder)</code></h3> <p>Now JUnit users can declare screenshooter like this:</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">MyTest</span> <span class="o">{</span> <span class="nd">@Rule</span> <span class="kd">public</span> <span class="nc">ScreenShooter</span> <span class="n">photographer</span> <span class="o">=</span> <span class="n">failedTests</span><span class="o">().</span><span class="na">to</span><span class="o">(</span><span class="s">"test-results/reports"</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>In most cases it’s not needed, because path for screenshots can be declared using system property: <code class="language-plaintext highlighter-rouge">-Dselenide.reports=test-results/reports</code> or programmatically: <code class="language-plaintext highlighter-rouge">Configuration.reportsFolder=test-results/reports</code>. So, the new method can only be useful if you need different paths for different tests.</p> <h2 id="bugfixes-and-improvements">Bugfixes and improvements</h2> <h3 id="method-download-throws-filenotfoundexception-if-server-returns-40x-error-or-runtimeexception-for-50x-status">Method <code class="language-plaintext highlighter-rouge">$.download()</code> throws <code class="language-plaintext highlighter-rouge">FileNotFoundException</code> (if server returns 40x error) or <code class="language-plaintext highlighter-rouge">RuntimeException</code> (for 50x status)</h3> <p>In older versions, method <code class="language-plaintext highlighter-rouge">$.download()</code> returned an empty file in case of server error during downloading file. It’s certainly not convenient for testing.</p> <h3 id="chrome-browser-window-is-also-maximized">Chrome browser window is also maximized.</h3> <p>Because of a bug in ChromeDriver Chrome browser window was not maximized. Now it is. Indeed I had to use java.awt black magic for this.</p> <h3 id="method-shouldhavetext-also-ignores-the-u00a0-character-so-called-non-breaking-space">Method <code class="language-plaintext highlighter-rouge">$.shouldHave(text())</code> also ignores the \u00a0 character (so called “non-breaking space”)</h3> <p>In older versions, a check <code class="language-plaintext highlighter-rouge">$(".error").shouldHave(text("Hello, Johny!"))</code> ignored spaces and tabs. But we forgot about the \u00a0 characters which is widely used in web - e.g. for formatting amounts and dates. For example, this check could 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">".amount"</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">"123.45 EUR"</span><span class="o">));</span> </code></pre></div></div> <p>Now it works.</p> <h3 id="improved-automatic-closing-of-browser-window-in-case-of-multi-threaded-tests-run-with-testng">Improved automatic closing of browser window in case of multi-threaded tests run with TestNG</h3> <p>In older versions, Selenide opened and closed browser in the same thread. In most cases it’s sufficient. <br /><br /> But folks found that TestNG executes tests and @AfterSuite methods in different threads. We had to rework this code. Now Selenide watches all threads and automatically closes unused browser windows once corresponding threads are done. <br /> P.S. Let me remind you that you <em>do not need</em> to manually close webdriver, because Selenide does it automatically. <br /></p> <h3 id="including-webdriver-exception">Including webdriver exception</h3> <p>When a check like <code class="language-plaintext highlighter-rouge">$.shouldBe(visible)</code> fails because of webdriver exception, this error is not ignored anymore, but added to a standard Selenide error message like <code class="language-plaintext highlighter-rouge">Element should be visible</code>. It can be possible if browser behaves incorrectly. For example, folks found that <code class="language-plaintext highlighter-rouge">IE</code> sometimes throws <code class="language-plaintext highlighter-rouge">InvalidSelectorException</code> for a valid XPath.</p> <h3 id="if-selenide-fails-to-take-screenshot-it-logs-corresponding-exception-with-stack-trace">If Selenide fails to take screenshot, it logs corresponding exception with stack trace.</h3> <p>Actually I am not sure that it’s really useful. To avoid spamming logs, Selenide writes stack trace only once (on the first error).</p> <h3 id="selenide-saves-page-source-in-correct-encoding-utf-8">Selenide saves page source in correct encoding (UTF-8)</h3> <p>In older versions, Selenide could store page HTML in wrong encoding, depending on default system preferences.</p> <h3 id="removed-info-messages-about-reportsurl-and-build_url">Removed INFO messages about “reportsUrl” and “BUILD_URL”</h3> <p>Some users were confused by these messages.</p> <p>Indeed, it’s a really fantastic feature: Selenide can automatically take screenshots and make them available as HTTP links in Jenkins reports. I will write a separate blog post about this feature.</p> <h3 id="using-jquery-word-instead-of-">Using “<code class="language-plaintext highlighter-rouge">jQuery</code>” word instead of “<code class="language-plaintext highlighter-rouge">$</code>”</h3> <p>Sometimes Selenide used character “<code class="language-plaintext highlighter-rouge">$</code>” to support javascript events. It could cause problems when testing applications using both <code class="language-plaintext highlighter-rouge">jQuery</code> and <code class="language-plaintext highlighter-rouge">Prototype</code> (or some other JS framework).</p> <h3 id="upgraded-to-selenium-2400-htmlunit-214-and-testng-688">Upgraded to Selenium 2.40.0, HtmlUnit 2.14 and TestNG 6.8.8</h3> <p>As usually, we upgraded to last versions of Selenium and TestNG.</p> <p>NB! In the latest TestNG 6.8.8 was removed JUnit support. So be careful if you use both TestNG and JUnit in your project, and the latter was loaded transitively. Now you will need to add JUnit dependency explicitly.</p> <p><br /> So, life is going on!</p> <p><br /></p> <p>And what’s new with you?</p> <p><br /></p> https://selenide.org/2014/03/15/selenide-2.9/ https://selenide.org/2014/03/15/selenide-2.9 2014-03-15T00:00:00+00:00 Selenide downloads: over 200 unique ips <p>As you probably know, the Central Maven Repo publishes download statistics for different artifacts.</p> <p><br /></p> <p>Today was published Selenide download statistics for February, 2014. The image below shows number of unique IPs that downloaded selenide.jar from the central maven repository.</p> <p><br /></p> <p>It seems that we have great success! Yeah!</p> <p><br /></p> <center> <img src="/images/2014/03/selenide_downloads.unique_ips.png" width="800" /> </center> <p><br /></p> https://selenide.org/2014/03/12/selenide-downloads/ https://selenide.org/2014/03/12/selenide-downloads 2014-03-12T00:00:00+00:00 Selenide in five minutes by Glen Smith <p>Wow!</p> <p>Glen Smith presented Selenide at Canberra JUG. This is a really great 5-min live demo of Selenide. It took only 5 minutes to tell, write and run a full working test for google image service. You know, it’s not that easy: there is Ajax under the hood…</p> <p><br /></p> <p>Please enjoy!</p> <p><br /></p> <center> <iframe src="//www.youtube.com/embed/6LW4h5y6Iw4" height="473" width="630" allowfullscreen="" frameborder="0"></iframe> <br /> Original blog post: [Selenide in Five Minutes: A lightning talk](http://blogs.bytecode.com.au/glen/2014/02/13/selenide-in-five-minutes-a-lightning-talk.html) </center> <p><br /></p> <p><a href="http://blogs.bytecode.com.au/glen/about">Glen Smith</a> is an Australian engineer, co-author of “Grails in Action” book.</p> <p>You can find more info in his <a href="http://blogs.bytecode.com.au/glen">blog</a>.</p> <p>Good job, <a href="https://twitter.com/glen_a_smith">@glen_a_smith</a>!</p> <p><img src="http://blogs.bytecode.com.au/glen/wp-content/uploads/2011/06/author.jpg" align="center" /></p> https://selenide.org/2014/03/11/selenide-in-5-minutes/ https://selenide.org/2014/03/11/selenide-in-5-minutes 2014-03-11T00:00:00+00:00 Selenide T-shirt <p>Hi seleniders!</p> <p>You could have noticed that Selenide has got a new logo and design.</p> <p>And even own T-shirts! Like real men!</p> <p>We will share three of these T-shirts next week on the <a href="http://xpdays.com.ua/program/">XP Days conference</a> in Kiev.</p> <p><a href="/images/2013/10/selenide_front.jpg"><img src="/images/2013/10/selenide_front.thumb.jpg" alt="front" /></a> <a href="/images/2013/10/selenide_back.jpg"><img src="/images/2013/10/selenide_back.thumb.jpg" alt="back" /></a></p> https://selenide.org/2013/10/04/selenide-tshirt/ https://selenide.org/2013/10/04/selenide-tshirt 2013-10-04T00:00:00+00:00 Selenide Harlem Shake <p>Good morning!</p> <p>This is a video demonstrating how easy is to start writing automated tests with Selenide.</p> <p>We wanted to make a screencast that would be short, funny and informative enough. By the way, this is a real-life project, not another “Hello World” application.</p> <p>Watch with sound!</p> <iframe src="//player.vimeo.com/video/73128965" width="500" height="281" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""> </iframe> <p> <a href="https://vimeo.com/73128965">Selenide Harlem Shake</a> from <a href="https://vimeo.com/user20427140">Selenide</a> on <a href="https://vimeo.com">Vimeo</a>. </p> https://selenide.org/2013/08/29/selenide-harlem-shake/ https://selenide.org/2013/08/29/selenide-harlem-shake 2013-08-29T00:00:00+00:00 Can PhantomJS take screenshots? <p>Many people think that PhantomJS (as a headless browser) cannot take screenshots.</p> <p>This is not true!</p> <p>According to <a href="https://github.com/ariya/phantomjs/wiki/Screen-Capture">PhantomJS documentation</a>, it can take screenshots.</p> <p>Let’s try to do that.</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="kd">public</span> <span class="kd">class</span> <span class="nc">TestPhantomScreenshot</span> <span class="o">{</span> <span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span> <span class="nc">System</span><span class="o">.</span><span class="na">setProperty</span><span class="o">(</span><span class="s">"browser"</span><span class="o">,</span> <span class="s">"phantomjs"</span><span class="o">);</span> <span class="n">open</span><span class="o">(</span><span class="s">"http://google.com"</span><span class="o">);</span> <span class="n">screenshot</span><span class="o">(</span><span class="s">"google-com-screenshot"</span><span class="o">);</span> <span class="n">close</span><span class="o">();</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div></div> <p>It works!</p> <p>Though, it does not work ideally. Well, screenshots of <a href="/images/2013/07/google-com-screenshot.png">google.com</a>, <a href="/images/2013/07/habrahabr-ru-screenshot.png">habrahabr.ru</a> and <a href="/images/2013/07/skype-com-screenshot.png">skype.com</a> look good, but screenshot of <a href="/images/2013/07/selenide-org-screenshot.png">selenide.org</a> is quite strange.</p> <p>Does it mean that PhantomJS is not mature enough yet? I don’t know. But at least PhantomJS can do screenshots.</p> <p><a href="/images/2013/07/google-com-screenshot.png"><img src="/images/2013/07/google-com-screenshot.thumb.png" alt="google.com" /></a> <a href="/images/2013/07/habrahabr-ru-screenshot.png"><img src="/images/2013/07/habrahabr-ru-screenshot.thumb.png" alt="habrahabr.ru" /></a> <a href="/images/2013/07/skype-com-screenshot.png"><img src="/images/2013/07/skype-com-screenshot.thumb.png" alt="skype.com" /></a> <a href="/images/2013/07/selenide-org-screenshot.png"><img src="/images/2013/07/selenide-org-screenshot.thumb.png" alt="selenide.org" /></a></p> https://selenide.org/2013/07/15/can-phantomjs-take-screenshots/ https://selenide.org/2013/07/15/can-phantomjs-take-screenshots 2013-07-15T00:00:00+00:00 Video: Selenide on SeleniumCamp 2013 <p>This is our talk about Selenide on <a href="http://seleniumcamp.com/materials/">SeleniumCamp 2013</a> conference in Kiev.</p> <p>The talk is in Russian.</p> <p>First part - introduction to Selenide:</p> <iframe src="//www.youtube.com/embed/4TegXkNWbqw" width="800" height="490" frameborder="0"></iframe> <p>Second part - live demonstration of Selenide:</p> <ul> <li>pair programming</li> <li>ping-pong programming</li> <li>programming a real internet bank</li> </ul> <iframe src="//www.youtube.com/embed/x3osTlsU82g" width="800" height="490" frameborder="0"></iframe> https://selenide.org/2013/05/09/video-selenide-on-seleniumcamp/ https://selenide.org/2013/05/09/video-selenide-on-seleniumcamp 2013-05-09T00:00:00+00:00 What is Selenide <p>Many of you have tried <a href="http://code.google.com/p/selenium/">Selenium WebDriver</a> - one of the most popular tools for UI Testing.</p> <p>Writing UI Tests is not simple. There are a number of typical problems, including Ajax, dynamic pages and timeouts. The goal of Selenide is to resolve these problems.</p> <p><img src="/images/selenide-logo-100x100.png" alt="right" /></p> <h3 id="what-is-selenide">What is Selenide</h3> <p><a href="https://selenide.org">Selenide</a> is a wrapper for Selenium WebDriver that allows you easier and faster writing of UI Tests. With Selenide you can concentrate on business logic instead of solving all these endless browser/ajax/timeouts problems.</p> <p>This is an example of UI Test. As you see, the amount of code is minimal. Just type <code class="language-plaintext highlighter-rouge">open</code> - and browser comes.</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">testLogin</span><span class="o">()</span> <span class="o">{</span> <span class="n">open</span><span class="o">(</span><span class="s">"/login"</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">"user.name"</span><span class="o">)).</span><span class="na">sendKeys</span><span class="o">(</span><span class="s">"johny"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#submitButton"</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">"#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">"Hello, Johny!"</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">shouldNotBe</span><span class="o">(</span><span class="n">visible</span><span class="o">);</span> <span class="o">}</span> </code></pre></div></div> <p>When you first execute <code class="language-plaintext highlighter-rouge">open</code>, Selenide automatically runs web browser and opens page <code class="language-plaintext highlighter-rouge">http://localhost:8080/login</code> (host and port are configurable). And closes the browser automatically when all tests are finished.</p> <h3 id="selenide-key-features">Selenide key features</h3> <p>Shortly, these are the key features of Selenide</p> <ul> <li>Concise API inspired by jQuery</li> <li>Automatic handling of most problems with Ajax, waiting and timeouts</li> <li>Automatic handling of browser lifecycle</li> <li>Automatic screenshots on test failures</li> </ul> <p>In short, the purpose of Selenide - is to <strong>focus on business logic</strong> and not to engage in perpetual annoying minor problems.</p> <h3 id="additional-methods">Additional methods</h3> <p>Selenide provides additional methods for actions that cannot be done with a single command in Selenium WebDriver. These are radiobutton selection, selectbox selection, taking screenshots, clearing browser cache etc.</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">canFillComplexForm</span><span class="o">()</span> <span class="o">{</span> <span class="n">open</span><span class="o">(</span><span class="s">"/client/registration"</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">"user.name"</span><span class="o">)).</span><span class="na">setValue</span><span class="o">(</span><span class="s">"johny"</span><span class="o">);</span> <span class="n">selectRadio</span><span class="o">(</span><span class="s">"user.gender"</span><span class="o">,</span> <span class="s">"male"</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">"user.securityQuestion"</span><span class="o">)).</span><span class="na">selectOption</span><span class="o">(</span><span class="s">"What is my first car?"</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">"user.preferredLayout"</span><span class="o">)).</span><span class="na">selectOptionByValue</span><span class="o">(</span><span class="s">"plain"</span><span class="o">);</span> <span class="err">$</span><span class="o">(</span><span class="s">"#submit"</span><span class="o">).</span><span class="na">followLink</span><span class="o">();</span> <span class="n">takeScreenShot</span><span class="o">(</span><span class="s">"complex-form.png"</span><span class="o">);</span> <span class="o">}</span> <span class="nd">@Before</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">clearCache</span><span class="o">()</span> <span class="o">{</span> <span class="n">clearBrowserCache</span><span class="o">();</span> <span class="o">}</span> </code></pre></div></div> <h3 id="how-selenide-overcomes-ajax">How Selenide overcomes Ajax?</h3> <p>Ajax is PITA (pain in the ass) for UI Testers.</p> <p>Nowadays most of the applications use Ajax. When testing web application that uses Ajax, you need to invent code that waits for something. Wait until button gets green, wait until div gets required text, or wait until error message disappears. You can find tons of web pages suggesting tricks how to make Selenium wait something.</p> <p>Selenide resolves this problem like no other. Unbelievably simple! While Selenium provides you a rich API for waiting different events <a href="http://xpinjection.com/2013/04/04/waits-and-timeouts-in-webdriver/">see this for example</a>, Selenide suggests you just to not bother. If you want to check that button is green, but button is not yet green, Selenide just waits until the button gets green. (Of course, timeout is configurable. Default is 4 seconds). It’s an unique solution - as easy and stable as possible.</p> <p>Enjoy code samples:</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">pageUsingAjax</span><span class="o">()</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="n">visible</span><span class="o">);</span> <span class="c1">// waits until elements appears</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">"Hello, Johny!"</span><span class="o">));</span> <span class="c1">// waits until elements gets text "Hello, Johny!"</span> <span class="err">$</span><span class="o">(</span><span class="s">"#login-button"</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-button"</span><span class="o">));</span> <span class="c1">// waits until button gets green</span> <span class="err">$</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">disabled</span><span class="o">);</span> <span class="c1">// waits until button gets disabled</span> <span class="err">$</span><span class="o">(</span><span class="s">".error"</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="c1">// waits until element disappears</span> <span class="err">$</span><span class="o">(</span><span class="s">".error"</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="c1">// try to the same with a standard Selenium WebDriver!</span> <span class="o">}</span> </code></pre></div></div> <h3 id="how-to-make-screenshots-automatically">How to make screenshots automatically?</h3> <p>That’s easy! If you are using JUnit, just add this line to your base test class:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nd">@Rule</span> <span class="kd">public</span> <span class="nc">ScreenShooter</span> <span class="n">makeScreenshotOnFailure</span> <span class="o">=</span> <span class="nc">ScreenShooter</span><span class="o">.</span><span class="na">failedTests</span><span class="o">();</span> </code></pre></div></div> <p>This line will cause Selenide to automatically take screenshot after every failed test. For your convenience, Selenide creates even 2 files: .PNG and .HTML.</p> <p>If you want to shot all tests (not only failed), you can use this line:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nd">@Rule</span> <span class="kd">public</span> <span class="nc">ScreenShooter</span> <span class="n">makeScreenshotOnEveryTest</span> <span class="o">=</span> <span class="nc">ScreenShooter</span><span class="o">.</span><span class="na">failedTests</span><span class="o">().</span><span class="na">succeededTests</span><span class="o">();</span> </code></pre></div></div> <p>TestNG users can add this annotation to their base test class:</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">ScreenShooter</span><span class="o">.</span><span class="na">class</span><span class="o">})</span> </code></pre></div></div> <h3 id="i-want-to-try-how-to-start">I want to try, how to start?</h3> <p>Just add Selenide dependency to your project:</p> <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;dependency&gt;</span> <span class="nt">&lt;groupId&gt;</span>com.codeborne<span class="nt">&lt;/groupId&gt;</span> <span class="nt">&lt;artifactId&gt;</span>selenide<span class="nt">&lt;/artifactId&gt;</span> <span class="nt">&lt;version&gt;</span>7.5.0<span class="nt">&lt;/version&gt;</span> <span class="nt">&lt;/dependency&gt;</span> </code></pre></div></div> <p>Import required classes:</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="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">Condition</span><span class="o">.*</span> </code></pre></div></div> <p>and it’s ready! Start writing tests!</p> <h3 id="why-yet-another-testing-library">Why yet another testing library?</h3> <p>We have been using Selenium in different projects. And we discovered that every time we need to write the same code in order to start browser, close browser, take screenshots and so one. You can find a huge amount of topics ala “How to do this and that in Selenium” with a huge amount of code that you need to copy-paste into your project.</p> <p>We asked yourself: why should UI Testing be so tedious? We decided to extract our repeating code into a separate open-source library. That’s how <a href="https://selenide.org">Selenide</a> was born.</p> <h3 id="does-somebody-use-selenide">Does somebody use Selenide?</h3> <p>Yes. In <a href="http://codeborne.com/" target="_blank">Codeborne</a> we have been using Selenide for 2 years in different project:</p> <ul> <li>Internet-banks</li> <li>Self-service portals</li> <li>etc.</li> </ul> <p>with different languages and testing frameworks:</p> <ul> <li>Java + ANT + JUnit</li> <li>Java + Gradle + JUnit</li> <li>Scala + ANT + ScalaTest</li> <li>Groovy + ANT</li> <li>etc.</li> </ul> <p>So you can be sure that Selenide is not just another raw open-source project. It’s actually used and supported.</p> <h3 id="show-me-a-working-example">Show me a working example!</h3> <p>You can find a reference open-source project that uses Selenide: <a href="https://github.com/asolntsev/hangman">Hangman game</a>.</p> <p>We have also created project <a href="https://github.com/selenide-examples">Selenide examples</a>, where you can find examples of using Selenide for testing different sites like <a href="https://github.com/selenide-examples/gmail">Gmail</a> and <a href="https://github.com/selenide-examples/google">Google</a>.</p> <h3 id="what-means-the-name-selenide">What means the name “Selenide”?</h3> <p>In chemistry, Selenide is chemical compound containing Selenium + something.</p> <p>So for UI Tests:</p> <ul> <li>Selenide = Selenium + JUnit</li> <li>Selenide = Selenium + TestNG</li> <li>Selenide = Selenium + ScalaTest</li> <li>Selenide = Selenium + whatever</li> </ul> <p>Enjoy the open-source chemistry!</p> <h3 id="share-your-experience-with-us">Share your experience with us!</h3> <p>We would be glad to get your feedback - tell us what you tried, how it worked. What succeeded, what failed? Feel free to write your feedback or questions to <a href="mailto:selenide@googlegroups.com">googlegroup</a> or <a href="mailto:andrei.solntsev@gmail.com">privately to me</a>!</p> https://selenide.org/2013/04/23/what-is-selenide/ https://selenide.org/2013/04/23/what-is-selenide 2013-04-23T00:00:00+00:00