<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Selenium – technical</title><link>https://trunk--polite-jelly-cc0866.netlify.app/categories/technical/</link><description>Recent content in technical on Selenium</description><generator>Hugo -- gohugo.io</generator><lastBuildDate>Wed, 16 Nov 2022 00:00:00 +0000</lastBuildDate><atom:link href="https://trunk--polite-jelly-cc0866.netlify.app/categories/technical/index.xml" rel="self" type="application/rss+xml"/><item><title>Blog: BELLATRIX Test Automation Framework for C# and JAVA</title><link>https://trunk--polite-jelly-cc0866.netlify.app/blog/2022/bellatrix-test-automation-framework/</link><pubDate>Wed, 16 Nov 2022 00:00:00 +0000</pubDate><guid>https://trunk--polite-jelly-cc0866.netlify.app/blog/2022/bellatrix-test-automation-framework/</guid><description>
&lt;p>Over the last decade, a large ecosystem of Open Source projects has sprouted up around Selenium. Selenium is often used for automating web applications for testing purposes, but it does not include a testing framework.
Nowadays, Selenium Ecosystem initiatives try to give popularity to popular open-source test automation frameworks maintained by people outside of the core Selenium maintainers.
One of these frameworks is BELLATRIX, invented by &lt;a href="https://www.linkedin.com/in/angelovstanton/">Anton Angelov&lt;/a>. It has two versions - C# and Java.
A testing framework is an abstraction in which common code provides generic functionality (which can be selectively overridden) for testing different aspects of our applications- UI, API, security, performance, and many others.&lt;/p>
&lt;h2 id="bellatrix-test-automation-framework">BELLATRIX Test Automation Framework&lt;/h2>
&lt;p>The first version of &lt;strong>&lt;a href="https://bellatrix.solutions/">BELLATRIX&lt;/a>&lt;/strong> appeared on 26 December 2017. It was available only for C# initially, but written on the new back then .NET Core, allowing the framework to be used on all major operating systems (cross-platform).
One huge advantage of BELLATRIX is its cross-technology readiness. It allows you to write tests for different technologies such as Web, Mobile, Desktop, and API. In BELLATRIX, we strive for the API for all modules to be as identical as possible.&lt;/p>
&lt;p>The usage is simple. We suggest cloning BELLATRIX as a GIT sub-module. Then, any customizations, tests, and project-specific plug-ins should be placed in a project outside the BELLATRIX cloned repository. This way, you can quickly update to the latest version.&lt;/p>
&lt;p>&lt;a href="https://bellatrix.solutions/">&lt;strong>BELLATRIX official website, download and releases info&lt;/strong>&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://github.com/AutomateThePlanet/BELLATRIX">&lt;strong>BELLATRIX official C# GitHub Page&lt;/strong>&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://github.com/AutomateThePlanet/BELLATRIX-Java">&lt;strong>BELLATRIX official Java GitHub Page&lt;/strong>&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://docs.bellatrix.solutions/overview/">&lt;strong>BELLATRIX C# Documentation&lt;/strong>&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://docs.java.bellatrix.solutions/overview/">&lt;strong>BELLATRIX Java Documentation&lt;/strong>&lt;/a>&lt;/p>
&lt;p>Let&amp;rsquo;s investigate how easy it is to create your first test with BELLATRIX in 15 minutes. The sample will showcase how to create a very basic test login into a website:
&lt;figure class="img-responsive w-50">
&lt;img src="https://trunk--polite-jelly-cc0866.netlify.app/blog/2022/bellatrix-test-automation-framework/login-form.png"/>
&lt;/figure>
&lt;/p>
&lt;ol>
&lt;li>Open the &lt;strong>BellatrixTestFramework.sln&lt;/strong>&lt;/li>
&lt;/ol>
&lt;figure class="img-responsive w-50">
&lt;img src="https://trunk--polite-jelly-cc0866.netlify.app/blog/2022/bellatrix-test-automation-framework/open_the_sln.png"/>
&lt;/figure>
&lt;ol start="2">
&lt;li>Under the &lt;strong>starthere&lt;/strong> folder, find the project you prefer: web, mobile, desktop, API&lt;/li>
&lt;/ol>
&lt;figure class="img-responsive w-50">
&lt;img src="https://trunk--polite-jelly-cc0866.netlify.app/blog/2022/bellatrix-test-automation-framework/bellatrix-projects-structure.png"/>
&lt;/figure>
&lt;ol start="3">
&lt;li>Open the &lt;strong>BellatrixLoginTest.cs&lt;/strong> file. There you will find a sample test automating the login.&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c4a000">[TestClass]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">class&lt;/span> &lt;span style="color:#000">LoginTestsMSTest&lt;/span> &lt;span style="color:#000;font-weight:bold">:&lt;/span> &lt;span style="color:#000">MSTest&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">WebTest&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">override&lt;/span> &lt;span style="color:#204a87;font-weight:bold">void&lt;/span> &lt;span style="color:#000">TestInit&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">App&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">Navigation&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">Navigate&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;http://demos.bellatrix.solutions/my-account/&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c4a000">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c4a000"> [TestMethod]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">void&lt;/span> &lt;span style="color:#000">SuccessfullyLoginToMyAccount&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">var&lt;/span> &lt;span style="color:#000">userNameField&lt;/span> &lt;span style="color:#000;font-weight:bold">=&lt;/span> &lt;span style="color:#000">App&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">Components&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">CreateById&lt;/span>&lt;span style="color:#000;font-weight:bold">&amp;lt;&lt;/span>&lt;span style="color:#000">TextField&lt;/span>&lt;span style="color:#000;font-weight:bold">&amp;gt;(&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;username&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">var&lt;/span> &lt;span style="color:#000">passwordField&lt;/span> &lt;span style="color:#000;font-weight:bold">=&lt;/span> &lt;span style="color:#000">App&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">Components&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">CreateById&lt;/span>&lt;span style="color:#000;font-weight:bold">&amp;lt;&lt;/span>&lt;span style="color:#000">Password&lt;/span>&lt;span style="color:#000;font-weight:bold">&amp;gt;(&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;password&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">var&lt;/span> &lt;span style="color:#000">loginButton&lt;/span> &lt;span style="color:#000;font-weight:bold">=&lt;/span> &lt;span style="color:#000">App&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">Components&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">CreateByXpath&lt;/span>&lt;span style="color:#000;font-weight:bold">&amp;lt;&lt;/span>&lt;span style="color:#000">Button&lt;/span>&lt;span style="color:#000;font-weight:bold">&amp;gt;(&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;//button[@name=&amp;#39;login&amp;#39;]&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">userNameField&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">SetText&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;info@yourverybusywebsite.com&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">passwordField&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">SetPassword&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;yourverysecretp4ssw0rd$&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">loginButton&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">Click&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">var&lt;/span> &lt;span style="color:#000">myAccountContentDiv&lt;/span> &lt;span style="color:#000;font-weight:bold">=&lt;/span> &lt;span style="color:#000">App&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">Components&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">CreateByClass&lt;/span>&lt;span style="color:#000;font-weight:bold">&amp;lt;&lt;/span>&lt;span style="color:#000">Div&lt;/span>&lt;span style="color:#000;font-weight:bold">&amp;gt;(&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;woocommerce-MyAccount-content&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">myAccountContentDiv&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">ValidateInnerTextContains&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Hello John&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">var&lt;/span> &lt;span style="color:#000">logoutLink&lt;/span> &lt;span style="color:#000;font-weight:bold">=&lt;/span> &lt;span style="color:#000">App&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">Components&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">CreateByInnerTextContaining&lt;/span>&lt;span style="color:#000;font-weight:bold">&amp;lt;&lt;/span>&lt;span style="color:#000">Anchor&lt;/span>&lt;span style="color:#000;font-weight:bold">&amp;gt;(&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Log out&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">logoutLink&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">ValidateIsVisible&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">logoutLink&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">Click&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>All available services are available through the main &lt;strong>App&lt;/strong> class. The &lt;strong>Components&lt;/strong> property provides various &lt;strong>Create&lt;/strong> methods for finding elements. They are generic, so you need to mention the type of the searched element. We have different elements because, for each of them, BELLATRIX offers various additional methods and assertions on top of native WebDriver methods.
The sample code uses MSTest as the default test framework, but by changing the attributes, it will also work out of the box for NUnit. Of course, you need to change the base class namespace too.&lt;/p>
&lt;h2 id="why-bellatrix">Why BELLATRIX?&lt;/h2>
&lt;p>Let&amp;rsquo;s quickly list some of the essential things the framework brings to the table:&lt;/p>
&lt;h3 id="multiple-test-environments-configuration">Multiple Test Environments Configuration&lt;/h3>
&lt;p>Every aspect of the framework can be controlled via a rich JSON configuration designed to work for many test environments. &lt;a href="https://docs.bellatrix.solutions/web-automation/control-browser/#configuration">&lt;strong>Web Project Configuration&lt;/strong>&lt;/a>.&lt;/p>
&lt;h3 id="customization">Customization&lt;/h3>
&lt;p>One of the hardest things to develop is to allow these generic frameworks to be extendable and customizable. Knowing how essential customization is, we utilize different ways to achieve it. The major one is about &lt;a href="https://bellatrix.solutions/features/web/extend-the-framework-to-fit-your-needs/">&lt;strong>writing your own plug-ins&lt;/strong>&lt;/a>.&lt;/p>
&lt;h3 id="test-reliability">Test Reliability&lt;/h3>
&lt;p>One of the biggest problems in test automation is handling timeouts and performing actions on elements that may not be on the page right now. BELLATRIX hides the complexity of searching and &lt;a href="https://bellatrix.solutions/features/web/boost-test-reliability/">&lt;strong>waiting for elements&lt;/strong>&lt;/a>. Furthermore, when you perform an action or assertion against an element, we guarantee that once returned, it will be present.&lt;/p>
&lt;p>A significant part of your tests are the assertions - checking whether some conditions are met. To handle such scenarios, we created elements &lt;strong>Validate&lt;/strong> methods. They internally handle the whole complexity of waiting for some condition to happen.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">updateCart&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">ValidateIsDisabled&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">totalSpan&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">ValidateInnerTextIs&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;120.00€&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">timeout&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">30&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">sleepInterval&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">2&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">messageAlert&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">ValidateIsNotVisible&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="complex-controls">Complex Controls&lt;/h3>
&lt;p>BELLATRIX provides API that makes handling HTML tables and grids much easier &lt;strong>&lt;a href="https://docs.bellatrix.solutions/web-automation/complex-components/">HTML tables and grids&lt;/a>&lt;/strong>.
&lt;figure class="img-responsive w-50">
&lt;img src="https://trunk--polite-jelly-cc0866.netlify.app/blog/2022/bellatrix-test-automation-framework/grid-html-example.png"/>
&lt;/figure>
Here is an example for asserting grid cells:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">TestGrid&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">ForEachCell&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">cell&lt;/span> &lt;span style="color:#000;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">cell&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">AssertFontSize&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;14px&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">TestGrid&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">GetCell&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Firstname&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">1&lt;/span>&lt;span style="color:#000;font-weight:bold">).&lt;/span>&lt;span style="color:#000">ValidateInnerTextIs&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Mary&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">TestGrid&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">GetCell&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#0000cf;font-weight:bold">0&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">1&lt;/span>&lt;span style="color:#000;font-weight:bold">).&lt;/span>&lt;span style="color:#000">ValidateInnerTextIs&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;John&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">TestGrid&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">GetCell&lt;/span>&lt;span style="color:#000;font-weight:bold">&amp;lt;&lt;/span>&lt;span style="color:#000">Employee&lt;/span>&lt;span style="color:#000;font-weight:bold">&amp;gt;(&lt;/span>&lt;span style="color:#000">cell&lt;/span> &lt;span style="color:#000;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">cell&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">PersonalEmail&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">1&lt;/span>&lt;span style="color:#000;font-weight:bold">).&lt;/span>&lt;span style="color:#000">ValidateInnerTextIs&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;mary@hotmail.com&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>There is much more complex stuff that you can do with both components so check the &lt;strong>&lt;a href="https://docs.bellatrix.solutions/web-automation/complex-components/">official documentation&lt;/a>&lt;/strong>.&lt;/p>
&lt;h2 id="integrations">Integrations&lt;/h2>
&lt;p>Seamlessly integrate the framework with your existing tools and processes. Execute tests in the clouds, distribute and publish test results in reporting solutions. Maybe the most significant differentiators of the framework are its many integrations with popular tools such as Jira/qTest/Allure/ReportPortal and clouds such as AWS, Microsoft Azure, + many more. All these integrations leverage BELLATRIX plug-in architecture. For example, we have plug-ins for automatically generating/updating test cases based on our automated tests in qTest and AzureDevops or similarly creating automatic bug reports with steps to reproduce in Jira or Azure.&lt;/p>
&lt;h3 id="dynamic-test-cases">Dynamic Test Cases&lt;/h3>
&lt;p>Dynamic test cases are a unique feature in BELLATRIX, where the framework automatically generates test cases in a popular test case management system based on your automated tests. It will populate the title, description, and other necessary properties automatically. Moreover, it will generate human-readable steps and expected results. The most significant benefit is that it will keep up to date with your auto-generated test cases over time, no matter what you change in your tests. It is an excellent functionality which allows the non-technical people of your company to see what your tests are doing.&lt;/p>
&lt;h3 id="ai-validation-of-pdfs-and-image">AI Validation of PDFs and Image&lt;/h3>
&lt;p>Azure Computer Vision is a service that can be used to extract printed and handwritten text from images and documents with mixed languages and writing styles. In contrast, Azure Form Recognizer is an AI-powered document extraction service that understands your document.
You are not limited to PDFs only. You can use the same feature for extracting text from complex images. BELLATRIX comes with similar functionality based on the AWS cloud.&lt;/p>
&lt;h3 id="email-testing">Email Testing&lt;/h3>
&lt;p>BELLATRIX offers a few utilities for email testing. There are a few scenarios where we need such integration. The first one is related to creating unique email inboxes and using them to submit various online forms. Later, we can read the emails via the services and check the content of the emails. It might be enough to verify the content via regular C#, or in some cases, we might need to interact with the email content in the browser.&lt;/p>
&lt;p>There are tons of other integrations that we use on a daily basis in many big enterprise projects, such as cloud secrets management for securely storing credentials and other secrets.
&lt;strong>&lt;a href="https://docs.bellatrix.solutions/product-integrations/">All BELLATRIX Integrations&lt;/a>&lt;/strong>&lt;/p>
&lt;p>Using BELLATRIX in your projects might save months/years of effort even if you have the required programming knowledge. This way, you can quickly focus on writing automated tests for your project.
Usually, there are 4-6 major releases each year, including all bug fixes and new features. Check our &lt;strong>&lt;a href="https://bellatrix.solutions/roadmap/release-3-6-0-0-chamaeleon/">release notes history&lt;/a>&lt;/strong>. The framework is fully covered with over 4000 automated tests and offers rich documentation. We make sure to merge the new feature branches only when we are sure that everything is working. If some issue emerges after a major release, it is quickly fixed within a few days.&lt;/p>
&lt;p>For feature requests or bug reports, you can submit them to our GitHub repositories. If you believe that the functionality you developed can be added to the CORE framework or you have a bug fix, please submit a PR so we can discuss it and potentially merge it. For anything else, you can reach us via our &lt;strong>&lt;a href="https://bellatrix.solutions/contact-us/">contact us form&lt;/a>&lt;/strong>.&lt;/p></description></item><item><title>Blog: Observability in Selenium 4</title><link>https://trunk--polite-jelly-cc0866.netlify.app/blog/2021/selenium-4-observability/</link><pubDate>Mon, 26 Apr 2021 00:00:00 +0000</pubDate><guid>https://trunk--polite-jelly-cc0866.netlify.app/blog/2021/selenium-4-observability/</guid><description>
&lt;p>Diagnosing problems when the Selenium server isn&amp;rsquo;t working has never been easy. With Selenium 4, we have integrated &lt;a href="https://opentelemetry.io/">OpenTelemetry&lt;/a> to help you troubleshoot issues, optimize performance, and provide visibility into the system. By making the Selenium server observable, we are putting more power into your hands.&lt;/p>
&lt;h3 id="need-for-observability">Need for Observability&lt;/h3>
&lt;p>Selenium server enables distributed testing. Instead of running the browsers for tests locally, the tests use a remote browser driver that points to a server. The server makes “&lt;strong>smart&lt;/strong>” decisions to run tests on different remote servers. Every such remote server is capable of hosting different types of browsers and browser versions.&lt;/p>
&lt;p>Selenium 3 uses Hub as the coordinator. It receives new session requests and directs them to the appropriate Node. The Node is the remote end where the browser itself runs.&lt;/p>
&lt;p>Selenium 4 extends this to provide users with a way to set up a full-blown distributed system. Essentially, &lt;a href="https://www.selenium.dev/documentation/en/grid/grid_4/components_of_a_grid/">Selenium 4&lt;/a> splits the Hub into different components with additional enhancements. However, the Node’s role remains the same. To ensure the backward compatibility and simplicity of setting up Grid, standalone and hub-node mode are also available in the new Selenium server.&lt;/p>
&lt;p>Now picture running a full-blown distributed Selenium Grid with hundreds of Nodes with different browsers and browser versions. Testing at scale in such an infrastructure will involve large volumes of requests. How can one keep track of these requests? Enter Selenium Observability!&lt;/p>
&lt;h3 id="how-does-selenium-provide-observability">How Does Selenium Provide Observability?&lt;/h3>
&lt;p>Selenium uses OpenTelemetry to instrument tracing and event logs. Tracing keeps track of a request’s lifecycle. As a request moves through the distributed system, the trace of the request will contain all the information of its crucial operations performed along the way. Such operations are known as spans. A span can record timed logs called events, which ideally encapsulate the current state of the system. These are event logs.&lt;/p>
&lt;p>By default, the Selenium server enables tracing. Selenium server can run in different modes:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.selenium.dev/documentation/en/grid/grid_4/setting_up_your_own_grid/#standalone-mode">Standalone&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.selenium.dev/documentation/en/grid/grid_4/setting_up_your_own_grid/#hub-and-node-mode">Hub and Node&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.selenium.dev/documentation/en/grid/grid_4/setting_up_your_own_grid/#distributed-mode">Fully Distributed&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/SeleniumHQ/docker-selenium#readme">Docker&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Tracing and event logs are available for all the modes. The simplest way to see traces is in the form of console logs. By default, the Selenium server prints logs at the INFO level and above. To pass a logging level of choice while running a Selenium Grid use the &lt;a href="https://www.selenium.dev/documentation/en/grid/grid_4/advanced_features/observability/#visualizing-traces">log-level&lt;/a> flag. Setting the log-level to FINE will display traces and event logs as console logs.&lt;/p>
&lt;p>For a large scale system, consuming traces as logs might not be efficient.
Visualizing and querying traces will quickly help troubleshoot a request failure easily. &lt;a href="https://www.jaegertracing.io/">Jaeger&lt;/a> seamlessly integrates with OpenTelemetry to provide a rich experience of querying, visualizing and collecting request traces.&lt;/p>
&lt;p>Run &lt;code> java -jar selenium-server-&amp;lt;selenium-version&amp;gt;.jar info tracing&lt;/code>.&lt;/p>
&lt;p>It provides detailed and updated instructions to set up Jaeger with the Selenium server.
Visualizing the traces makes it easy to interpret a trace and understand request flow. Now Grid users can effortlessly trace a request, drill down into an error or query them to observe what is happening.&lt;/p>
&lt;figure>
&lt;img src="https://trunk--polite-jelly-cc0866.netlify.app/images/blog/2021/trace.png"
alt="Trace example"/>
&lt;/figure>
&lt;p>Refer to &lt;a href="https://www.selenium.dev/documentation/en/grid/grid_4/advanced_features/observability/">Selenium Observability&lt;/a> for details.&lt;/p>
&lt;h3 id="full-stack-tracing">Full-Stack Tracing&lt;/h3>
&lt;p>The Java client binding supports tracing. Full-stack tracing allows tracing a request from the client to the server and back. Though the client is a single component, the client trace will contain spans that help build the request. It is easier to locate a client-side problem and fix the test if needed.&lt;/p>
&lt;p>We already saw how the server supports tracing and how to leverage it. For the client-side, add the Opentelemetry dependency to your project setup and add the necessary system properties to export the traces to Jaeger. Refer to &lt;a href="https://www.selenium.dev/documentation/en/remote_webdriver/remote_webdriver_client/#tracing-client-requests">RemoteWebdriver client&lt;/a> for detailed instructions.&lt;/p>
&lt;h3 id="leveraging-traces-and-event-logs">Leveraging Traces and Event Logs&lt;/h3>
&lt;p>The key to fixing a problem lies in knowing the error. For a known error situation, the event logs have you covered. It provides detailed error information and stack traces. Query the collected traces for a time range by the error code to identify the frequency of the error. It will help determine if the error is transient or not and accordingly take action.&lt;/p>
&lt;figure>
&lt;img src="https://trunk--polite-jelly-cc0866.netlify.app/images/blog/2021/error-event-log.png"
alt="Error event log example"/>
&lt;/figure>
&lt;p>Observe the request latency to identify potential bottlenecks. Each trace will also contain time taken by each span. The issue could be in the underlying infrastructure setup, the network latency, or the code itself. Irrespective of the cause, it is easier to identify the problem area.&lt;/p>
&lt;p>Observability is slowly becoming a must-have property of a system. Selenium is now observable! Go ahead try it out. Let us know if you find anything that requires improvement on our end.&lt;/p></description></item><item><title>Blog: Browser Testing and Tools WG Meeting @ TPAC 2020</title><link>https://trunk--polite-jelly-cc0866.netlify.app/blog/2020/webdriver-tpac-meeting-2020/</link><pubDate>Thu, 29 Oct 2020 00:00:00 +0000</pubDate><guid>https://trunk--polite-jelly-cc0866.netlify.app/blog/2020/webdriver-tpac-meeting-2020/</guid><description>
&lt;p>It&amp;rsquo;s that time of the year where working groups from the W3C meet up to discuss the various standards that
are being worked on.&lt;/p>
&lt;p>Within the Browser Testing and Tools Working Group, there are 2 different standards.&lt;/p>
&lt;p>We have:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://w3c.github.io/webdriver/">WebDriver&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://w3c.github.io/webdriver-bidi">WebDriver-Bidi&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>The first is what is commonly supported by the Selenium Project and has support from Apple, Mozilla, Microsoft, and Google in their browsers. It is also supported by various Selenium in the cloud providers like Sauce Labs and BrowserStack.&lt;/p>
&lt;p>As the world has moved on we have felt the need to add new APIs and move Selenium to be more event-driven. This is where we are learning, and collaborating, with projects like Puppeteer to make sure that we can improve the Browser Automation space. This is where the &lt;a href="https://w3c.github.io/webdriver-bidi">WebDriver-Bidi&lt;/a> Specification comes in. It has broad support from the browser vendors so you can use official browsers and not be limited by the JavaScript sandbox. Some of the newer frameworks can&amp;rsquo;t guarantee that.&lt;/p>
&lt;p>If you&amp;rsquo;re curious about we discussed this week, feel free to read it up on the &lt;a href="https://www.w3.org/wiki/WebDriver/2020-TPAC">W3 Wiki&lt;/a>.&lt;/p>
&lt;p>This post was originally shared on David Burns&amp;rsquo; &lt;a href="https://www.theautomatedtester.co.uk/blog/2020/webdriver-tpac-meeting-2020/">Blog&lt;/a>&lt;/p></description></item><item><title>Blog: How to delete your master branch</title><link>https://trunk--polite-jelly-cc0866.netlify.app/blog/2020/how_to_delete_your_master_branch/</link><pubDate>Thu, 27 Aug 2020 00:00:00 +0000</pubDate><guid>https://trunk--polite-jelly-cc0866.netlify.app/blog/2020/how_to_delete_your_master_branch/</guid><description>
&lt;img src="https://trunk--polite-jelly-cc0866.netlify.app/blog/2020/how_to_delete_your_master_branch/featured_how_to_delete_your_master_branch_2_hu8faf28356324fb6e8174b5f26ec63c14_49150_640x0_resize_catmullrom_3.png" width="640" height="457"/>
&lt;figure class="img-responsive text-center">
&lt;img src="https://trunk--polite-jelly-cc0866.netlify.app/blog/2020/how_to_delete_your_master_branch/featured_how_to_delete_your_master_branch_2.png"/>
&lt;/figure>
&lt;p>At the Selenium project we practice
&lt;a href="https://trunkbaseddevelopment.com/">trunk based development&lt;/a>, in which &lt;code>trunk&lt;/code> is the
usual name of the default git branch of the repository. However, when the project was
moved to GitHub, the repository followed the traditional use of &lt;code>master&lt;/code> as a name for
the default git branch.&lt;/p>
&lt;p>With the intention of making the Selenium project an even more inclusive place where
everyone is welcome, a decision was made to use &lt;code>trunk&lt;/code> as the default git branch and,
after the switch, delete the &lt;code>master&lt;/code> branch. This change created a few challenges.
This blog post will point out a few things you should watch out if you want to make
the same change in your GitHub repository.&lt;/p>
&lt;h4 id="broken-links">Broken Links&lt;/h4>
&lt;p>It is common to link specific parts of the code in the documentation, and that link
normally contains the branch name. Double-check your documentation for links pointing
to files living on the &lt;code>master&lt;/code> branch, as they could end up as broken links after
the change.&lt;/p>
&lt;h4 id="mentions-to-the-branch-name">Mentions to the branch name&lt;/h4>
&lt;p>Similarly, the branch name gets mentioned in different parts of the repository,
such as code comments, contribution instructions, issue and pull request templates,
and the readme. Don’t forget to check these places.&lt;/p>
&lt;h4 id="github-repository-badges">GitHub repository badges&lt;/h4>
&lt;p>We all like to show off how our GitHub repository is doing by adding as many badges
as we can. In many cases, those badges report a build status that depends on the branch
where the build was executed. Make sure your Travis/CircleCI/GitHub Actions badge is
pointing to the new branch.&lt;/p>
&lt;h4 id="continuous-integration-setups">Continuous Integration setups&lt;/h4>
&lt;p>A good practice in open source is to have a continuous integration setup to run the
builds, execute tests and potentially do automated releases. Nowadays, the CI
configuration is done in files (e.g. .travis.yml for Travis), and one important
piece of that configuration is the name of the branch where the build should be
executed. Similar to the previous point, double check that your new branch name
is property configured in your CI integration.&lt;/p>
&lt;h4 id="build-scripts">Build scripts&lt;/h4>
&lt;p>At the Selenium project, we have a few custom build scripts that get executed
through the continuous integration setup. An example is the script that generates
the docs for the Java, Ruby and Python bindings. This script needs to know the code’s
branch name to generate the docs. If you have scripts with similar purposes, check
them after changing the branch name.&lt;/p>
&lt;h4 id="open-pull-requests">Open pull requests&lt;/h4>
&lt;p>All of the tasks above could probably be achieved with a text editor and a massive,
but careful, “search and replace” across all the files in the repository. In short,
the process we followed to move to the new branch &lt;code>trunk&lt;/code> was:&lt;/p>
&lt;ol>
&lt;li>Create a new branch called &lt;code>trunk&lt;/code>, based on the &lt;code>master&lt;/code> branch.&lt;/li>
&lt;li>Do all the items described in the previous points.&lt;/li>
&lt;li>Commit and push those changes.&lt;/li>
&lt;li>Delete the &lt;code>master&lt;/code> branch.&lt;/li>
&lt;/ol>
&lt;p>Nevertheless, one thing happened that we did not expect: after deleting the &lt;code>master&lt;/code>
branch, all the open pull requests got closed. This made sense, since they were all
targeting the &lt;code>master&lt;/code> branch. Therefore, before deleting your &lt;code>master&lt;/code> branch, double
check and, if needed, edit the open pull requests so they target the new branch.&lt;/p>
&lt;figure class="img-responsive text-center">
&lt;img src="https://trunk--polite-jelly-cc0866.netlify.app/blog/2020/how_to_delete_your_master_branch/how_to_delete_your_master_branch_1.png"/>
&lt;/figure>
&lt;p>It goes without saying that the name of your new branch can be any name that works
well for your context and environment. For example, the
&lt;a href="https://github.com/SeleniumHQ/seleniumhq.github.io">repository&lt;/a> that has the
contents of the Selenium &lt;a href="https://www.selenium.dev/">website&lt;/a> uses now &lt;code>dev&lt;/code> as the
branch with the website source files and &lt;code>publish&lt;/code> as the branch with the generated
static website that gets &lt;em>published&lt;/em>.&lt;/p>
&lt;p>These are our lessons learned during the process of deleting the &lt;code>master&lt;/code> branch in
all the major repositories under the &lt;a href="https://github.com/seleniumhq/">SeleniumHQ GitHub&lt;/a>
organization. I hope they are helpful if you decide to move from &lt;code>master&lt;/code> as a name
for your default branch.&lt;/p>
&lt;p>&lt;em>This was originally posted at &lt;a href="https://opensource.saucelabs.com/blog/how_to_delete_your_master_branch/">https://opensource.saucelabs.com/blog/how_to_delete_your_master_branch/&lt;/a>&lt;/em>&lt;/p></description></item><item><title>Blog: Moving to Trunk</title><link>https://trunk--polite-jelly-cc0866.netlify.app/blog/2020/moving-to-trunk-development/</link><pubDate>Wed, 01 Jul 2020 00:00:00 +0000</pubDate><guid>https://trunk--polite-jelly-cc0866.netlify.app/blog/2020/moving-to-trunk-development/</guid><description>
&lt;p>Since the project started we have been following &lt;a href="https://trunkbaseddevelopment.com/">trunk based development&lt;/a>. This was a very natural fit when we were using SVN over a decade ago on Google Code.&lt;/p>
&lt;p>As Google Code shut down we moved to GitHub and the git model of doing things. We moved there mostly due to the gravity that GitHub had created in Open Source projects.&lt;/p>
&lt;p>This meant that we followed the standard use of &lt;code>master&lt;/code> as our trunk to work off. Now that GitHub, and services that use GitHub, have improved support for non-master branches as default we are moving our default branch to &lt;code>trunk&lt;/code>. It describes how we, as a project, work and is a more inclusive term.&lt;/p>
&lt;p>If you have pull requests based on &lt;code>master&lt;/code> we will see about moving that over to the &lt;code>trunk&lt;/code> branch ourselves. If we can&amp;rsquo;t, we may ask you to help with the rebasing.&lt;/p>
&lt;p>We, as a project, want to make our community inclusive and this is just one step in making sure we are. Other steps we taking are improving our Code of Conduct and Community Guidelines.&lt;/p>
&lt;p>Join us on Slack or IRC if you wish to discuss this further.&lt;/p></description></item><item><title>Blog: Source Control</title><link>https://trunk--polite-jelly-cc0866.netlify.app/blog/2013/source-control/</link><pubDate>Mon, 14 Jan 2013 00:00:00 +0000</pubDate><guid>https://trunk--polite-jelly-cc0866.netlify.app/blog/2013/source-control/</guid><description>
&lt;p>This short technical note is to announce that the Selenium project is now using &lt;a href="https://code.google.com/p/selenium/source/checkout">git on Google Code&lt;/a> in place of subversion.&lt;/p>
&lt;p>The move has been a long time in the making, and it’s largely thanks to the efforts of &lt;a href="https://twitter.com/krosenvold">Kristian Rosenvold&lt;/a> that we’ve been able to do the migration and retain the project history. The project owes him a huge thank you! We’re in the process of migrating the last bits and pieces (none of which are user facing), so there may be some last minute turbulence as we settle everything down.&lt;/p>
&lt;p>Although the canonical source will be on &lt;a href="http://selenium.googlecode.com/">Google Code&lt;/a>, we’re working on setting up a github mirror. We’ll announce the location of that once it’s set up.&lt;/p></description></item><item><title>Blog: Going Atomic: How</title><link>https://trunk--polite-jelly-cc0866.netlify.app/blog/2010/going-atomic-how/</link><pubDate>Sun, 05 Sep 2010 00:00:00 +0000</pubDate><guid>https://trunk--polite-jelly-cc0866.netlify.app/blog/2010/going-atomic-how/</guid><description>
&lt;p>This is the second of my technical posts. Again, if you’re interested in the internal workings of Selenium 2, then please skip straight to something else. If you’re interested in how and why we made some of the technical decisions on the project, keep reading….&lt;/p>
&lt;p>We left our intrepid heroes in a tight spot: they’d decided to write a shared library of code, to be used by the various webdriver implementations and selenium core, but the requirements for doing this seemed to be at odds with it actually happening.&lt;/p>
&lt;p>Fortunately, at about the same time we started down this path, Google Open Sourced the &lt;a href="closure-compiler.googlecode.com">Closure compiler&lt;/a>. This is a Javascript compiler that takes as input a set of Javascript files, and which outputs Javascript. It can be configured to either pass the code through untouched into a single file, or it can compile a script aggressively, removing unused code-paths and minifying the output as much as possible. The Closure compiler is used on a lot of Google products, so we know that it’s reliable and consistent.&lt;/p>
&lt;p>In order to get the best out of the Closure compiler, we’re writing the atoms using the &lt;a href="closure-library.googlecode.com">Closure library&lt;/a>. This isn’t as well known as some of the other JS libraries out there, but it’s solid, well tested and is being actively developed. It also features an easy-to-use extension of JsUnit, which makes writing tests a far simpler task than might otherwise be the case, and it has an easy to use mechanism for modularizing code.&lt;/p>
&lt;p>So, given that we could compile a single Javascript function (and it’s dependencies) into a minified fragment of JS, we were all set, right? Not quite.&lt;/p>
&lt;p>The problem is that the atoms are being extracted from two frameworks that have a different way of viewing the world. As an example, Selenium 1’s “&lt;a href="http://selenium.googlecode.com/svn/trunk/docs/api/java/com/thoughtworks/selenium/Selenium.html#getAttribute(java.lang.String)">getAttribute&lt;/a>” method only returns the value of a particular attribute, whereas WebDriver’s “&lt;a href="http://selenium.googlecode.com/svn/trunk/docs/api/java/org/openqa/selenium/WebElement.html#getAttribute(java.lang.String)">getAttribute&lt;/a>” method will return the value of either a property or an attribute (because sometimes it’s hard to remember whether something is an attribute or a property of an element)&lt;/p>
&lt;p>As with all problems in computer science, an extra level of indirection is used to solve this issue.&lt;/p>
&lt;p>We’re busy implementing the expected behaviour of both &lt;a href="http://code.google.com/p/selenium/source/browse/#svn/trunk/common/src/js/webdriver">WebDriver’s&lt;/a> and &lt;a href="http://code.google.com/p/selenium/source/browse/#svn/trunk/common/src/js/selenium%3Fstate%3Dclosed">Selenium’s&lt;/a> API on top of the atoms.&lt;/p>
&lt;p>There is, of course, the obvious question about how we get this carefully compressed JS into a driver. One option would be to include the raw Javascript as files in each language binding, and pull them in as required. That’s possible, but it would make each language binding bloated, and would introduce a lot of duplication. The alternative is to push the atoms as far into the driver as possible, and this is what we do. As part of the build process for webdriver, we take the compressed JS and convert it into a form that can be consumed by a particular driver. For example, for the IE driver, we convert them into constants in a &lt;a href="http://code.google.com/p/selenium/source/browse/trunk/jobbie/src/cpp/InternetExplorerDriver/atoms.h">C header file&lt;/a>. These constants can then be referred to by the driver and converted back into a script than be executed via the same mechanism that is used by “executeScript”.&lt;/p>
&lt;p>What do we gain from this seemingly baroque approach? Other than the ability to share the same code between drivers? Many things. The cost of maintenance drops dramatically as we can fix a bug in one place and have that fix be picked up by every driver. Because we’re working in pure JS and just querying the DOM, we can run the unit tests in a browser whilst we’re developing the code. This leads to a very tight feedback cycle. It also makes it easier for developers not familiar with the code to take a look at how we do things, and send us patches (always appreciated!) Finally, we can ensure a consistency of result.&lt;/p>
&lt;p>Right, any questions?&lt;/p></description></item><item><title>Blog: Going Atomic: Why?</title><link>https://trunk--polite-jelly-cc0866.netlify.app/blog/2010/going-atomic-why/</link><pubDate>Mon, 16 Aug 2010 00:00:00 +0000</pubDate><guid>https://trunk--polite-jelly-cc0866.netlify.app/blog/2010/going-atomic-why/</guid><description>
&lt;p>This is the first in a series of technical posts by me about the internals of Selenium WebDriver. If you’re not interested in technical nitty-gritty, then feel free to step away now.&lt;/p>
&lt;p>Still here? Excellent.&lt;/p>
&lt;p>Let’s take a step back to just before the Selenium and WebDriver projects merged. There were, very obviously, two separate codebases. Looking closer and with a slightly different perspective, there were more than this. We used the test suites for webdriver to define the behaviour for multiple, largely independent, driver codebases. The &lt;a href="http://code.google.com/p/selenium/source/browse/#svn/trunk/jobbie">IE driver&lt;/a> was written in C, the HtmlUnit driver in Java and the &lt;a href="http://code.google.com/p/selenium/source/browse/#svn/trunk/firefox">Firefox driver&lt;/a> is largely Javascript, and so on.&lt;/p>
&lt;p>This means that there was a lot of “congruent code”: code that performed the same function but was implemented in a different way. The natural result of this was there was the possibility for behaviour to diverge between drivers. Worse, it meant that when a bug was found, we had to check it in every browser, and it wasn’t certain that an individual could actually fix the code. After all, not everyone is comfortable writing in all the languages we use on the project, or is au fait with all the technologies. For an Open Source project like Selenium, this is a major problem: we rely on a relatively small core of key developers backed up with a far larger team of individuals submitting small changes and fixes. Anything that makes it harder for us to function effectively as a development community is a Bad Thing.&lt;/p>
&lt;p>So, we wanted a way off the island; a mechanism that would make it easy to share code between the various drivers and selenium core, that allowed us to fix a bug in one place only and have that fix ripple out to every driver that made use of this mechanism. More importantly, it had to be easy to use, and for someone not familiar with a raft of languages and technologies to quickly get started with.&lt;/p>
&lt;p>What would this mechanism look like? Well, there’s a few things that feed into this, but the most important one, was that a majority of the code we’d think of merging was querying the state of the browser (“find an element”, “get the value of this attribute”) and, as Jason Huggins would point out to me at the drop of a hat, the natural language for querying the state of a browser is Javascript. One of the nice things with Javascript is that it’s possible to get a nice, fast development cycle going in it. Just modify a test, save and then hit “refresh” in the browser. That’s kind of attractive. Better still, there are a lot of developers familiar with Javascript.&lt;/p>
&lt;p>So, we decided to use Javascript.&lt;/p>
&lt;p>Because this shared code was to be composed of the smallest useful fragments of functionality required for browser automation we decided to refer to them as “Browser Automation Atoms”, or “atoms” for short. Rather than write them from scratch, the easiest thing to do was to extract them from the existing code — this is stuff that’s been battle-tested, so we know it’s robust.&lt;/p>
&lt;p>There was one very obvious fly in the ointment: not every driver is written in Javascript. Although we have a &lt;a href="http://selenium.googlecode.com/svn/trunk/docs/api/java/org/openqa/selenium/JavascriptExecutor.html">mechanism available&lt;/a> in every browser for executing JS, it’s wildly inefficient to dump an enormous lump of code on to the JS engine of the browser whenever you want to query the DOM. After all, most of the code would not be needed, and not all JS engines have been created equal. Some are blazingly fast. Others, not so much.&lt;/p>
&lt;p>It would also be nice to break the code up into manageably-sized modules, rather than being in a single, monolithic file, which implies some clever “module loading” capability. Except this code isn’t always going to be executing inside an environment where writing “script” tags to load additional scripts is possible. You can’t do that in the guts of a firefox extension, though you can load files other ways. However we tie modules together will need to cope with that.&lt;/p>
&lt;p>Ah! These opposing requirements: small modules containing the functions we want to use, no extraneous code, and for everything to be in a single file in order to minimize the pain of loading additional modules. That doesn’t sound like a very compatible list. How we resolved those differences is the topic of my next post….&lt;/p></description></item><item><title>Blog: How to use Selenium 2 with Maven</title><link>https://trunk--polite-jelly-cc0866.netlify.app/blog/2010/how-to-use-selenium-2-with-maven/</link><pubDate>Fri, 30 Jul 2010 00:00:00 +0000</pubDate><guid>https://trunk--polite-jelly-cc0866.netlify.app/blog/2010/how-to-use-selenium-2-with-maven/</guid><description>
&lt;p>There are several ways to use Selenium 2:&lt;/p>
&lt;ol>
&lt;li>If you don’t have Selenium 1.x legacy code, you might want to directly use on of the new WebDriver implemenations like ChromeDriver, HtmlUnitDriver, FirefoxDriver, or InternetExplorerDriver which provide a nice, small and easy to learn API.&lt;/li>
&lt;li>If you have Selenium 1.x legacy code, you can still use the well known DefaultSelenium class or the new WebDriverBackedSelenium, which extends DefaultSelenium but uses one of the WebDriver implementations internally.&lt;/li>
&lt;/ol>
&lt;p>Whichever option you prefer, if you have want to use Maven, all you need to do is add the following dependency to your pom.xml:&lt;/p>
&lt;pre>&lt;code>&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.seleniumhq.selenium&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;selenium&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;2.0a5&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code>&lt;/pre>
&lt;p>If you know, that you will only use a certain WebDriver implementation, e.g. the FirefoxDriver, you don’t need to depend on the selenium artifact (which has dependencies to all WebDriver implementations as well as the support classes). Instead you can add the dependency to just the artifact you need, e.g.&lt;/p>
&lt;pre>&lt;code>&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.seleniumhq.selenium&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;selenium-firefox-driver&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;2.0a5&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code>&lt;/pre>
&lt;p>When using a WebDriver implementation, there is no need to start a Selenium server – the browser will be directly started and remote controlled.&lt;/p>
&lt;p>But if you are using DefaultSelenium (or the RemoteWebDriver implementation), you still need to start a Selenium server.&lt;/p>
&lt;p>The best way is to download the &lt;a href="http://code.google.com/p/selenium/downloads/detail?name=selenium-server-standalone-2.0a5.jar">standalone Selenium server jar&lt;/a> and just use it.&lt;/p>
&lt;p>Furthermore you can also embed the Selenium server into your own project, if you add the following dependency to your pom.xml:&lt;/p>
&lt;pre>&lt;code>&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.seleniumhq.selenium&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;selenium-server&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;2.0a5&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code>&lt;/pre>
&lt;p>Now you can create a SeleniumServer instance yourself and start it.&lt;/p>
&lt;p>Be aware, that the selenium-server artifact has a dependency to the servlet-api-2.5 artifact, which you need to exclude, if your project will be run in a web application container.&lt;/p>
&lt;p>Well, I hope that covers everything you need to know on how to use Selenium 2 with Maven.&lt;/p>
&lt;p>Michael&lt;/p></description></item></channel></rss>