<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Endtest</title>
    <description>The latest articles on DEV Community by Endtest (@endtest).</description>
    <link>https://dev.to/endtest</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F762%2F845ee33b-cb17-4546-86c8-99d943d48ce1.png</url>
      <title>DEV Community: Endtest</title>
      <link>https://dev.to/endtest</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/endtest"/>
    <language>en</language>
    <item>
      <title>How To Record Automated Tests For Mobile Apps </title>
      <dc:creator>endtest</dc:creator>
      <pubDate>Wed, 18 Mar 2020 13:48:00 +0000</pubDate>
      <link>https://dev.to/endtest/how-to-record-automated-tests-for-mobile-apps-4am5</link>
      <guid>https://dev.to/endtest/how-to-record-automated-tests-for-mobile-apps-4am5</guid>
      <description>&lt;p&gt;&lt;a href="https://endtest.io"&gt;Endtest&lt;/a&gt; allows you to create, manage and execute Automated Tests, without having to write any code. &lt;/p&gt;

&lt;p&gt;You can use the open-source &lt;a href="https://chrome.google.com/webstore/detail/endtest-codeless-automate/jbdgfkeimppmnfemmgfafiomihlibdfa"&gt;Endtest Chrome Extension&lt;/a&gt; to record a test for your website directly in the browser.&lt;/p&gt;

&lt;p&gt;But did you know that you can also record tests for native and hybrid Android and iOS applications? 🤗&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--E8Lku-eM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2e8y5lrvmehbiefvx6ky.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--E8Lku-eM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2e8y5lrvmehbiefvx6ky.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And you do that direcly from your browser.&lt;/p&gt;

&lt;p&gt;What? 😱&lt;/p&gt;

&lt;p&gt;That's right.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://endtest.io/guides/docs/how-to-create-mobile-tests/"&gt;Mobile Recorder&lt;/a&gt; allows you to record tests for native and hybrid mobile apps, directly in your browser. &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What are the steps?&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;You upload the APK or IPA file. &lt;/li&gt;
&lt;li&gt;The app is installed on a real mobile device.&lt;/li&gt;
&lt;li&gt;The information for each element is extracted.&lt;/li&gt;
&lt;li&gt;An interactive preview is shown in real-time in your browser window.&lt;/li&gt;
&lt;li&gt;You record the test. &lt;/li&gt;
&lt;li&gt;You save the test.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/4vqxABcfpac"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;But how does it locate the elements?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;It's no secret that our engine for Mobile Tests is using &lt;a href="http://appium.io/"&gt;Appium&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We just fetch the locators for the elements that you interact with. &lt;/p&gt;

&lt;p&gt;If we would rely on image recognition, that would lead to brittle tests.&lt;/p&gt;

&lt;p&gt;We fetch the following locators:&lt;br&gt;
• ID&lt;br&gt;
• Accessibility ID&lt;br&gt;
• Name&lt;br&gt;
• Class Name&lt;br&gt;
• XPath&lt;br&gt;
• Coordinates&lt;/p&gt;

&lt;p&gt;If you're not using Coordinates, you can easily execute the same test on different devices.&lt;/p&gt;

&lt;p&gt;Coordinates are only used in extreme cases, when no other unique locator is available.&lt;/p&gt;

&lt;p&gt;You can find more details in our &lt;a href="https://endtest.io/guides/docs/how-to-create-mobile-tests/"&gt;Documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>mobile</category>
      <category>android</category>
      <category>ios</category>
    </item>
    <item>
      <title>Building The Most Powerful Test Recorder On The Market</title>
      <dc:creator>endtest</dc:creator>
      <pubDate>Fri, 21 Feb 2020 15:09:14 +0000</pubDate>
      <link>https://dev.to/endtest/building-the-most-powerful-test-recorder-on-the-market-5ggd</link>
      <guid>https://dev.to/endtest/building-the-most-powerful-test-recorder-on-the-market-5ggd</guid>
      <description>&lt;h3&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://endtest.io"&gt;Endtest&lt;/a&gt; allows you to create, manage and execute Automated Tests, without having to write any code. &lt;/p&gt;

&lt;p&gt;You can use the &lt;a href="https://chrome.google.com/webstore/detail/endtest-codeless-automate/jbdgfkeimppmnfemmgfafiomihlibdfa"&gt;Endtest Chrome Extension&lt;/a&gt; to record a test directly in the browser.&lt;/p&gt;

&lt;p&gt;And yes, it's open-source and free to use. 🤗&lt;/p&gt;

&lt;p&gt;This extension works by recording all the steps that a user performs in the browser and converts those steps into an automated test.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/cFboO4O5moU"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. How we record the steps&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We record the following actions:&lt;br&gt;
• Click&lt;br&gt;
• Right Click&lt;br&gt;
• Write Text&lt;br&gt;
• Select option from dropdown&lt;br&gt;
• Press Key&lt;br&gt;
• Hover&lt;br&gt;
• Scroll&lt;br&gt;
• Open tab&lt;br&gt;
• Close tab&lt;br&gt;
• Switch to next tab&lt;br&gt;
• Switch to previous tab&lt;br&gt;
• Go back&lt;br&gt;
• Go forward&lt;br&gt;
• Access URL from navigation bar&lt;br&gt;
• Entering an iframe&lt;br&gt;
• Exiting an iframe&lt;br&gt;
... and many more&lt;/p&gt;

&lt;p&gt;Since we're talking about a Chrome extension, the only way to detect such events is through JavaScript and the &lt;a href="https://developer.chrome.com/extensions"&gt;Chrome API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We used different JavaScript event listeners such as onclick, onchange, onkeyup, onmousemove, etc to figure out what the user does. &lt;/p&gt;

&lt;p&gt;It's important to distinguish between the different actions. &lt;/p&gt;

&lt;p&gt;For example, when a user is typing inside an input, you need to register that as a "Write Text" action. &lt;/p&gt;

&lt;p&gt;But when the user pressed the Enter key or the Escape key, you need to register that as a "Press Key" action.&lt;/p&gt;

&lt;p&gt;The user has the option to enable or disable the detection of Hover and Scroll events, since they're not relevant in all situations. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6tM7lioj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mkv7pmp8q4qzvh9m58xe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6tM7lioj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mkv7pmp8q4qzvh9m58xe.png" alt="Endtest Recorder Settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even if a user enables the detection of Hover events, they will only be logged if the duration of Hover is above a certain number of miliseconds. &lt;/p&gt;

&lt;p&gt;This is done to avoid recording unnecessary Hover events when the user is simply moving the pointer.&lt;/p&gt;

&lt;p&gt;The Chrome API is used to detect actions which cannot be detected with JavaScript, such as when the user is opening a new tab or switching focus to a different tab.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;2. Getting the right permissions&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Being able to record everything that a user does in the browser might sound like a job for the NSA.&lt;/p&gt;

&lt;p&gt;Luckily, Chrome is smart enough to let you declare what permissions you need in the manifest.json file.&lt;/p&gt;

&lt;p&gt;They also review those permissions when you publish the extension in the Chrome Web Store. &lt;/p&gt;

&lt;p&gt;And the user is informed about those permissions when installing the extension.&lt;/p&gt;

&lt;p&gt;Here is what the permissions for our extension like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;permissions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;activeTab&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;all_urls&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cookies&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;storage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tabs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;webNavigation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;3. Locating the elements&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;It's no secret that our engine for Web Tests is using Selenium.&lt;/p&gt;

&lt;p&gt;That's why we need to fetch locators for the elements that the users interacts with. &lt;/p&gt;

&lt;p&gt;If we would rely on coordinates or image recognition, that would lead to brittle tests.&lt;/p&gt;

&lt;p&gt;We fetch the following locators:&lt;br&gt;
• ID&lt;br&gt;
• Name&lt;br&gt;
• CSS Selector&lt;br&gt;
• XPath&lt;/p&gt;

&lt;p&gt;Fetching the ID for an element might seem as simple as this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onclick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;the_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But there are plenty of tricky situations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The element does not have an ID&lt;/li&gt;
&lt;li&gt;Multiple elements share the same ID&lt;/li&gt;
&lt;li&gt;The ID is generated dynamically and changes with each refresh&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This means that we always check for uniqueness and we try to detect and avoid using IDs which are dynamic. &lt;/p&gt;

&lt;p&gt;The same rules apply for the Name attribute. &lt;/p&gt;

&lt;p&gt;CSS Selectors can be generated by using the using the attributes from an element and the parent nodes.&lt;/p&gt;

&lt;p&gt;Let's take a look at this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"login-form"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"mat-input-6"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"mat-input-9"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Password"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can easily spot that the IDs are dynamic, so we have to avoid them.&lt;/p&gt;

&lt;p&gt;The basic CSS Selector for the Email input would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;&lt;span class="nx"&gt;nth&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But we can easily construct something more reliable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Most people ditch XPaths for CSS Selectors, thinking that they're just as powerful, but slower. Big mistake.&lt;/p&gt;

&lt;p&gt;XPaths have some hidden tricks up their sleeves. &lt;/p&gt;

&lt;p&gt;The XPath equivalent to the previous CSS Selector would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xpath"&gt;&lt;code&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="na"&gt;@placeholder&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Email"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But here's a situation where XPath can save your life:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"items"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"item"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Apple&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"item"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Orange&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"item"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Banana&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let's try to fetch a locator for the Orange list item.&lt;/p&gt;

&lt;p&gt;CSS Selectors do not have the ability to locate an element based on the text, but XPaths do. &lt;/p&gt;

&lt;p&gt;The XPath for the Orange list item is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xpath"&gt;&lt;code&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;'Orange'&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We even offer advanced settings for detecting locators:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OPNEyf-Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rbgoqzwq7c5yvmq0ghz6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OPNEyf-Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rbgoqzwq7c5yvmq0ghz6.png" alt="Endtest Recorder"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using classes in CSS Selectors and XPaths can also be tricky, since they can only appear in the element when you click on it. &lt;/p&gt;

&lt;p&gt;Let's take a look at this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"login-form"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We want to locate the input type="button" element. &lt;/p&gt;

&lt;p&gt;But when we click on that input, it gets 2 extra classes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"login-form active focus"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Since we're recording the event at the moment of the click, our Chrome Extension would record the element as having 2 extra classes.&lt;/p&gt;

&lt;p&gt;If this would happen, our engine would throw an "Element not found" error when the test would be executed, since those 2 extra classes are not appended if the element isn't clicked. &lt;/p&gt;

&lt;p&gt;That's why allow the users to have a list of classes that our Chrome Extension can simply ignore:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kw62hq-q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yp5r7qd97ey8qlul4c05.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kw62hq-q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yp5r7qd97ey8qlul4c05.png" alt="Endtest Chrome Extension Classes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Going the extra mile&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We always make sure our users get the best experience.&lt;/p&gt;

&lt;p&gt;Steps for taking screenshots and adding assertions can be added directly from the recorder. &lt;/p&gt;

&lt;p&gt;The recording process can also be paused and resumed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BE7oxqEG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yw4s98e8be0hohdfbzfy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BE7oxqEG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yw4s98e8be0hohdfbzfy.png" alt="Endtest Recorder"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find more details in our &lt;a href="https://endtest.io/guides/docs/how-to-create-web-tests/"&gt;Documentation&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Q&amp;amp;A&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. Why do we also offer a cross-browser cloud infrastructure?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;We take testing very seriously.&lt;/p&gt;

&lt;p&gt;That's why our cloud platform offers real browsers on Windows and macOS machines and mobile devices. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rtQ3k8yV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cx4qm6rde0hduxi5e4vv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rtQ3k8yV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cx4qm6rde0hduxi5e4vv.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We encourage developers to avoid using headless browsers on Linux machines for their automated tests, since those browsers do not have the same behavior as the real browsers used by users.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2. Why record the tests with JavaScript and execute them with Selenium?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Since our recorder had to be a Chrome extension, we had no other choice than to use JavaScript.&lt;/p&gt;

&lt;p&gt;Our engine for Web Tests is using Selenium, because it's open-source, constantly improved, mimics real user behavior and it works with all the major browsers.&lt;/p&gt;

&lt;p&gt;We advise developers to avoid using JavaScript-based libraries for executing automated tests in the UI, since those libraries have severe limitations and do not mimic real user behavior. &lt;/p&gt;

&lt;p&gt;For example, a JavaScript-based library for testing the UI can easily click on an element which is completely covered by another element. &lt;br&gt;
A real user and a Selenium test cannot do that.&lt;/p&gt;

&lt;p&gt;A JavaScript library for testing the UI cannot perform file uploads, cannot manage iframes and cannot manage multiple browser tabs. &lt;/p&gt;

&lt;p&gt;Currently, there isn't any JavaScript library for UI testing that works on all the major browsers and devices. &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>testing</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to integrate Endtest with BrowserStack</title>
      <dc:creator>Klaus</dc:creator>
      <pubDate>Wed, 25 Sep 2019 14:25:54 +0000</pubDate>
      <link>https://dev.to/endtest/how-to-integrate-endtest-with-browserstack-2gkj</link>
      <guid>https://dev.to/endtest/how-to-integrate-endtest-with-browserstack-2gkj</guid>
      <description>&lt;h3&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://endtest.io" rel="noopener noreferrer"&gt;Endtest&lt;/a&gt; allows you to create, manage and execute Automated Tests, without having to write any code. &lt;/p&gt;

&lt;p&gt;By integrating with &lt;a href="https://www.browserstack.com/" rel="noopener noreferrer"&gt;BrowserStack&lt;/a&gt;, you can execute Mobile Tests created with Endtest on a range of real Android and iOS mobile devices offered by BrowserStack.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Getting Started&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;1) Go to your &lt;strong&gt;BrowserStack&lt;/strong&gt; account.&lt;br&gt;
2) Click on &lt;strong&gt;App Automate&lt;/strong&gt; from the &lt;strong&gt;Products&lt;/strong&gt; section:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fpa2x1o3afik565slagjr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fpa2x1o3afik565slagjr.png" alt="BrowserStack App Automate"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3) Click on the &lt;strong&gt;Show&lt;/strong&gt; button from the &lt;strong&gt;Username and Access Keys&lt;/strong&gt; section from the left side of the page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fisjvsfcdhd57sqkaymb0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fisjvsfcdhd57sqkaymb0.png" alt="BrowserStack App Automate"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4) Go to the &lt;strong&gt;Settings&lt;/strong&gt; page from &lt;a href="https://endtest.io" rel="noopener noreferrer"&gt;Endtest&lt;/a&gt;.&lt;br&gt;
5) Add the &lt;strong&gt;Username&lt;/strong&gt; and &lt;strong&gt;Access Key&lt;/strong&gt; from BrowserStack App Automate in the BrowserStack User and BrowserStack Key inputs from the Endtest Settings page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F6pf5qsifvp6nqhkawouz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F6pf5qsifvp6nqhkawouz.png" alt="Endtest BrowserStack"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;6) Click on the &lt;strong&gt;Save&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;Nice job! Your Endtest account is now connected with your BrowserStack account.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Running your first test&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;1) Upload your APK or IPA file in the &lt;strong&gt;Drive&lt;/strong&gt; section from Endtest.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F0fmm95fgewc7c6xhlnmy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F0fmm95fgewc7c6xhlnmy.png" alt="Endtest Drive"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2) After that, go to the &lt;strong&gt;Mobile Tests&lt;/strong&gt; section and click on the Run button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5w45idfu6aep1dp2iqgk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5w45idfu6aep1dp2iqgk.png" alt="Endtest Execution"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3) Select &lt;strong&gt;BrowserStack&lt;/strong&gt; from the &lt;strong&gt;Grid&lt;/strong&gt; dropdown.&lt;/p&gt;

&lt;p&gt;4) Select the &lt;strong&gt;Platform&lt;/strong&gt; and the &lt;strong&gt;Real Device&lt;/strong&gt; on which you want to execute your test on.&lt;/p&gt;

&lt;p&gt;5) Select your APK file in the &lt;strong&gt;APK Download URL&lt;/strong&gt; input.&lt;br&gt;
If you select an iOS device, the &lt;strong&gt;APK Download URL&lt;/strong&gt; input would be replaced with the &lt;strong&gt;IPA Download URL&lt;/strong&gt; input.&lt;/p&gt;

&lt;p&gt;After starting the test execution, you will be redirected to the Results section where you'll get live video and all the results, logs and details in real-time.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>testing</category>
      <category>productivity</category>
      <category>devops</category>
    </item>
    <item>
      <title>Finding Elements in iframes with Selenium</title>
      <dc:creator>Klaus</dc:creator>
      <pubDate>Tue, 06 Aug 2019 12:21:58 +0000</pubDate>
      <link>https://dev.to/endtest/finding-elements-in-iframes-with-selenium-6al</link>
      <guid>https://dev.to/endtest/finding-elements-in-iframes-with-selenium-6al</guid>
      <description>&lt;p&gt;Anyone who is using &lt;strong&gt;&lt;a href="https://www.seleniumhq.org/"&gt;Selenium&lt;/a&gt;&lt;/strong&gt; has encountered a scenario where they have to deal with an iframe. &lt;/p&gt;

&lt;p&gt;There is no automatic way of detecting that the element you're looking for is inside an iframe.  &lt;/p&gt;

&lt;p&gt;The error message only says 'Element not found'. &lt;/p&gt;

&lt;p&gt;You're the one who's going to have to look in the Browser Console and figure out that your element is inside an iframe.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--U4GpmfOC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/obteyh9wuqh9milmj0jw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--U4GpmfOC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/obteyh9wuqh9milmj0jw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's create a test for the &lt;strong&gt;&lt;a href="https://stripe-payments-demo.appspot.com/"&gt;Stripe Payments Demo&lt;/a&gt;&lt;/strong&gt; which has an iframe.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cDrEk8YR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/v0328429z67s2l7cwr5c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cDrEk8YR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/v0328429z67s2l7cwr5c.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'll also be making some comparisons between Selenium and &lt;strong&gt;&lt;a href="https://endtest.io"&gt;Endtest&lt;/a&gt;&lt;/strong&gt;:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/4DIVKcs--TA"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;An iframe (inline frame) places another HTML document in a frame.&lt;/p&gt;

&lt;p&gt;You need to change the focus of Selenium from one HTML document to another.&lt;/p&gt;

&lt;p&gt;In our case, the only element which is inside the iframe is the &lt;strong&gt;Card&lt;/strong&gt; input.&lt;/p&gt;

&lt;p&gt;I used Python:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;driver.get("&lt;a href="https://stripe-payments-demo.appspot.com%22"&gt;https://stripe-payments-demo.appspot.com"&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;nameElement = driver.find_element_by_name("name")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;emailElement = driver.find_element_by_name("email")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;addressElement = driver.find_element_by_name("address")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;cityElement = driver.find_element_by_name("city")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;stateElement = driver.find_element_by_name("state")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;zipElement = driver.find_element_by_name("postal_code")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;countryElement = driver.find_element_by_name("country")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;iframeElement = driver.find_element_by_name("__privateStripeFrame5")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;cardElement = driver.find_element_by_name("cardnumber)&lt;/em&gt;&lt;br&gt;
&lt;em&gt;submitButton = driver.find_element_by_css_selector("#payment-form &amp;gt; button")&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;nameElement.send_keys("Klaus Werner")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;emailElement.send_keys("&lt;a href="mailto:klaus.werner@example.com"&gt;klaus.werner@example.com&lt;/a&gt;")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;addressElement.send_keys("Random Street")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;cityElement.send_keys("San Francisco")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;stateElement.send_keys("CA")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;zipElement.send_keys("94107")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;countryElement.select_by_value("US")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;driver.switch_to.frame(iframeElement)&lt;/em&gt;&lt;br&gt;
&lt;em&gt;cardElement.send_keys("4111 1111 1111 1111")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;driver.switch_to.default_content()&lt;/em&gt;&lt;br&gt;
&lt;em&gt;submitButton.click()&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Notice how I switched to the iframe before writing in the Card input?&lt;/p&gt;

&lt;p&gt;And I also switched back to the main page after that. &lt;/p&gt;

&lt;p&gt;It's a bit easier to deal with iframes if you're using &lt;strong&gt;&lt;a href="https://endtest.io"&gt;Endtest&lt;/a&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Hc_1j2eo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ffuis31rf1nquye71xpm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Hc_1j2eo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ffuis31rf1nquye71xpm.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since you're planning to run that test multiple times, you should generate a random email address and store it in a variable. &lt;/p&gt;

&lt;p&gt;You can even test that email with the &lt;strong&gt;&lt;a href="https://endtest.io/mailbox"&gt;Endtest Mailbox&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/K3k-f9vB8Dc"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>testing</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title> Puppeteer vs Selenium</title>
      <dc:creator>Klaus</dc:creator>
      <pubDate>Mon, 15 Jul 2019 19:55:39 +0000</pubDate>
      <link>https://dev.to/endtest/puppeteer-vs-selenium-1938</link>
      <guid>https://dev.to/endtest/puppeteer-vs-selenium-1938</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;a&gt;Puppeteer&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href="https://www.seleniumhq.org/"&gt;Selenium&lt;/a&gt;&lt;/strong&gt; are both popular, powerful and widely used solutions for automating web applications.&lt;/p&gt;

&lt;p&gt;But which one should YOU use?&lt;/p&gt;

&lt;p&gt;The answer depends on your specific needs.&lt;/p&gt;

&lt;p&gt;Choosing the wrong option could delay or worse, sabotage your automated testing project.&lt;/p&gt;

&lt;p&gt;I'll share my own opinion at the end of this article.&lt;/p&gt;

&lt;p&gt;Here are some PROS and CONS for both of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Puppeteer&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;PROS&lt;/strong&gt;&lt;br&gt;
• Faster than Selenium&lt;br&gt;
• Easy to install&lt;br&gt;
• Written and maintained by the Google Chrome devs&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CONS&lt;/strong&gt;&lt;br&gt;
• Works only with Chrome&lt;br&gt;
• The only supported language is Node.js&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Selenium&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;PROS&lt;/strong&gt;&lt;br&gt;
• Works with most browsers&lt;br&gt;
• Multi-language support&lt;br&gt;
• Huge community of users&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CONS&lt;/strong&gt;&lt;br&gt;
• Difficult to run on all browsers&lt;br&gt;
• A bit slower than Puppeteer&lt;/p&gt;

&lt;p&gt;To sum it up, Puppeteer is faster than Selenium, but it works only with Chrome, while Selenium works with Chrome, Firefox, Safari, Internet Explorer and Edge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now, for my opinion: both solutions are outdated and built with the narrow mindset of developers who refuse to see beyond their code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It may sound lazy, but I believe that a solution for automated testing should be like a washing machine: it should give me enough flexibility to choose different inputs and settings, but it shouldn't make me pump the water with one hand and spin the drum with the other. &lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;What both solutions are missing:&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;• Video Recording functionality&lt;br&gt;
• Turnkey Machine Learning&lt;br&gt;
• Integrated Email Testing option&lt;br&gt;
• Screenshot Comparison feature&lt;br&gt;
• Automatic Smart Waiting&lt;br&gt;
• Structured results&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Other issues with Selenium and Puppeteer:&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;• Difficult to upload files in a test&lt;br&gt;
• Difficult to deal with iframes&lt;br&gt;
• Difficult to integrate with your CI/CD system&lt;br&gt;
• Difficult to configure Element Load Timeout &lt;/p&gt;

&lt;p&gt;If you're looking for a better alternative, try &lt;strong&gt;&lt;a href="https://endtest.io"&gt;Endtest&lt;/a&gt;&lt;/strong&gt;.&lt;br&gt;
It has Puppeteer's speed, it supports Selenium's browsers AND it has all the features that they're missing.&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/4DIVKcs--TA"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>testing</category>
      <category>productivity</category>
      <category>devops</category>
    </item>
    <item>
      <title>Testing Emails with Selenium</title>
      <dc:creator>Klaus</dc:creator>
      <pubDate>Fri, 12 Jul 2019 12:47:46 +0000</pubDate>
      <link>https://dev.to/endtest/testing-emails-with-selenium-5h62</link>
      <guid>https://dev.to/endtest/testing-emails-with-selenium-5h62</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.seleniumhq.org/" rel="noopener noreferrer"&gt;Selenium&lt;/a&gt;&lt;/strong&gt; is widely used, but it's a little known fact that you can use it to test anything built with HTML and CSS, including &lt;strong&gt;&lt;a href="https://dev.to/razgandeanu/testing-chrome-extensions-with-selenium-491b"&gt;Chrome Extensions&lt;/a&gt;&lt;/strong&gt; and Emails.&lt;/p&gt;

&lt;p&gt;We'll create a simple test for the &lt;strong&gt;&lt;a href="https://swit.io/register" rel="noopener noreferrer"&gt;Register&lt;/a&gt;&lt;/strong&gt; page from &lt;strong&gt;&lt;a href="https://swit.io" rel="noopener noreferrer"&gt;Swit&lt;/a&gt;&lt;/strong&gt; and then we'll test the email that we receive. &lt;/p&gt;

&lt;p&gt;I'll also be making some comparisons between Selenium and &lt;strong&gt;&lt;a href="https://endtest.io" rel="noopener noreferrer"&gt;Endtest&lt;/a&gt;&lt;/strong&gt;:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/K3k-f9vB8Dc"&gt;
&lt;/iframe&gt;
&lt;br&gt;
Selenium can only interact with HTML elements if they're in a browser.&lt;/p&gt;

&lt;p&gt;This means that we'll have to open our email in a browser.&lt;/p&gt;

&lt;p&gt;Luckily, anyone can use the &lt;strong&gt;&lt;a href="https://endtest.io/mailbox" rel="noopener noreferrer"&gt;Endtest Mailbox&lt;/a&gt;&lt;/strong&gt; for free.&lt;/p&gt;

&lt;p&gt;The way it works is similar to a disposable email service.&lt;br&gt;
Simply send your email(s) to a &lt;a href="mailto:username@endtest.io"&gt;username@endtest.io&lt;/a&gt; email address.&lt;/p&gt;

&lt;p&gt;The username can be anything you choose.&lt;br&gt;
For instance, you can choose something like &lt;a href="mailto:jim32328@endtest.io"&gt;jim32328@endtest.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can access the Inbox for that email address on that page.&lt;/p&gt;

&lt;p&gt;Just add the email parameter in the URL, like this:&lt;br&gt;
&lt;a href="https://endtest.io/mailbox?email=jim32328@endtest.io" rel="noopener noreferrer"&gt;https://endtest.io/mailbox?email=jim32328@endtest.io&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Please note that the emails will be deleted after 2 hours.&lt;/p&gt;

&lt;p&gt;But for now, let's get back the Register page from Swit:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fn3sp106b8rtu7akrbysq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fn3sp106b8rtu7akrbysq.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;driver.get("&lt;a href="https://swit.io/register%22" rel="noopener noreferrer"&gt;https://swit.io/register"&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;firstName = driver.find_element_by_id("firstName")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;lastName = driver.find_element_by_id("lastName")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;email = driver.find_element_by_id("id")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;password = driver.find_element_by_id("password")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;confirmPassword = driver.find_element_by_id("confirmPassword")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;submitButton = driver.find_element_by_class_name("button--important")&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;firstName.send_keys("Klaus")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;lastName.send_keys("Werner")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;email.send_keys("&lt;a href="mailto:klaus123@endtest.io"&gt;klaus123@endtest.io&lt;/a&gt;")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;password.send_keys("Password123")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;confirmPassword.send_keys("Password123")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;submitButton.click()&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And here is the result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F6iixa4v57gb55gdt8zze.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F6iixa4v57gb55gdt8zze.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, if we want to check that email, we have to go to:&lt;br&gt;
&lt;a href="https://endtest.io/mailbox?email=klaus123@endtest.io" rel="noopener noreferrer"&gt;https://endtest.io/mailbox?email=klaus123@endtest.io&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;And we'll be able to open our email:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ffc386rjj9thtwtryi9ww.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ffc386rjj9thtwtryi9ww.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We just have to write that part with Selenium:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;driver.get("&lt;a href="https://endtest.io/mailbox?email=klaus123@endtest.io%22" rel="noopener noreferrer"&gt;https://endtest.io/mailbox?email=klaus123@endtest.io"&lt;/a&gt;)&lt;/em&gt;&lt;br&gt;
&lt;em&gt;email = driver.find_element_by_class_name("email_item")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;email.click()&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Since you're planning to run that test multiple times, you should generate a random email and store it in a variable and then append it to the Endtest Mailbox URL.&lt;/p&gt;

&lt;p&gt;If you're looking for a better Selenium alternative, switch to &lt;strong&gt;&lt;a href="https://endtest.io" rel="noopener noreferrer"&gt;Endtest&lt;/a&gt;&lt;/strong&gt;.&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/4DIVKcs--TA"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>testing</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>A Practical Guide for Finding Elements with Selenium</title>
      <dc:creator>Klaus</dc:creator>
      <pubDate>Wed, 12 Jun 2019 10:39:04 +0000</pubDate>
      <link>https://dev.to/endtest/a-practical-guide-for-finding-elements-with-selenium-4djf</link>
      <guid>https://dev.to/endtest/a-practical-guide-for-finding-elements-with-selenium-4djf</guid>
      <description>&lt;p&gt;This article is for anyone who just started using &lt;strong&gt;&lt;a href="https://www.seleniumhq.org/" rel="noopener noreferrer"&gt;Selenium&lt;/a&gt;&lt;/strong&gt; and wants to know the best ways to find elements.&lt;/p&gt;

&lt;p&gt;The key here is to find the most stable and reliable locator for each element.&lt;/p&gt;

&lt;p&gt;Keep in mind that asking Selenium to locate an element is like telling someone from out of town how to find a certain coffee shop in your city.&lt;/p&gt;

&lt;p&gt;We'll be using the &lt;strong&gt;&lt;a href="https://github.com/join" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/strong&gt; Sign Up page as an example.&lt;/p&gt;

&lt;p&gt;I'll also be making some comparisons between Selenium and &lt;strong&gt;&lt;a href="https://endtest.io" rel="noopener noreferrer"&gt;Endtest&lt;/a&gt;&lt;/strong&gt;:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/4DIVKcs--TA"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;We're going to use different locator types to find the Username input:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find Element By ID&lt;/li&gt;
&lt;li&gt;Find Element By Name&lt;/li&gt;
&lt;li&gt;Find Element By Class Name&lt;/li&gt;
&lt;li&gt;Find Element By XPath&lt;/li&gt;
&lt;li&gt;Find Element By CSS Selector&lt;/li&gt;
&lt;li&gt;Find Element By Link Text&lt;/li&gt;
&lt;li&gt;Find Element By Partial Link Text&lt;/li&gt;
&lt;li&gt;Find Element By Tag Name&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuh9esbc1pczc68fkoyag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuh9esbc1pczc68fkoyag.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1) Find Element By ID&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Always the first choice.&lt;/p&gt;

&lt;p&gt;In order to get the ID of your element, you just have to right click on your element and click on the &lt;strong&gt;Inspect&lt;/strong&gt; option.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ifw2iw32s73c2w98ky4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ifw2iw32s73c2w98ky4.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The structure of your element will be highlighted in the console:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr4ixh7thtl3cb1osnm38.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr4ixh7thtl3cb1osnm38.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It seems that our element has the following ID: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;user_login&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This means that your line of code will look like this: &lt;/p&gt;

&lt;p&gt;&lt;em&gt;username = driver.find_element_by_id("user_login")&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Since an ID should be unique on a page, it's the most reliable locator type that you can use.&lt;/p&gt;

&lt;p&gt;It's like having only one Starbucks in your city and telling your friends to meet you there, they can't miss.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2) Find Element By Name&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Just as good as ID, but you won't encounter it as often as you'd expect.&lt;/p&gt;

&lt;p&gt;Elements from forms usually have the &lt;strong&gt;Name&lt;/strong&gt; attribute.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw8bkpu0z8jyc9ok3jx45.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw8bkpu0z8jyc9ok3jx45.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can easily see that our element has the following Name: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;user[login]&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;username = driver.find_element_by_name("user[login]")&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3) Find Element By Class Name&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Not so reliable, since a Class Name is usually shared by multiple elements.&lt;/p&gt;

&lt;p&gt;We can easily see that our element has the following Class Name: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;form-control&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And if we take a closer look at the rest of the inputs from that form, we'll see that all of them have the &lt;strong&gt;form-control&lt;/strong&gt; Class Name.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;username = driver.find_element_by_class_name("form-control")&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This means that the you won't be able to locate that Username input with the Class Name locator type, since Selenium will throw an error.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://endtest.io" rel="noopener noreferrer"&gt;Endtest&lt;/a&gt;&lt;/strong&gt; has a more elegant approach here than Selenium.&lt;br&gt;
If you provide that Class Name, it will only give you a warning, telling you how many elements it found with that Class Name and that the first one will be used.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzudheio2suuwzh4ouvhm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzudheio2suuwzh4ouvhm.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If Starbucks had a Class Name, it would probably be coffee-shop. &lt;br&gt;
If you tell your friend &lt;strong&gt;Meet me at that coffee shop&lt;/strong&gt;, they might not know which one you're talking about.&lt;/p&gt;

&lt;p&gt;The most common mistake done by beginners is extracting all the Class Names instead of just one. &lt;/p&gt;

&lt;p&gt;Let's take a look at this element:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4apewv7qxfytusyl4pa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4apewv7qxfytusyl4pa.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A novice user might say that the element has the following Class Name:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HeaderMenu-link d-inline-block no-underline border border-gray-dark&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But it actually has 5 different Class Names:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;HeaderMenu-link&lt;/em&gt;&lt;br&gt;
&lt;em&gt;d-inline-block&lt;/em&gt;&lt;br&gt;
&lt;em&gt;no-underline&lt;/em&gt; &lt;br&gt;
&lt;em&gt;border&lt;/em&gt;&lt;br&gt;
&lt;em&gt;border-gray-dark&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;That's right, Class Names are separated by spaces. &lt;/p&gt;

&lt;p&gt;Selenium does not have a validation for that, but &lt;strong&gt;&lt;a href="https://endtest.io" rel="noopener noreferrer"&gt;Endtest&lt;/a&gt;&lt;/strong&gt; does:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuvsdm7c9e7xyozy2lk3q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuvsdm7c9e7xyozy2lk3q.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;4) Find Element By XPath&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You simply can't avoid having to use XPath for at least some elements.&lt;br&gt;
It's not as bad as they say. &lt;/p&gt;

&lt;p&gt;An XPath is like a route. There are a lot of routes that your friend can take to get to that Starbucks. &lt;/p&gt;

&lt;p&gt;Usually, an XPath looks something like this:&lt;br&gt;
&lt;strong&gt;/html/body/div[4]/main/div/div/div[1]/p&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The fastest way to get the XPath is from the Chrome console:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3nv5rvs24g7insra14q5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3nv5rvs24g7insra14q5.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case, we got the following XPath:  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;//*[&lt;a class="mentioned-user" href="https://dev.to/id"&gt;@id&lt;/a&gt;="user_login"]&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have a stable ID, you shouldn't bother to use XPath. &lt;/p&gt;

&lt;p&gt;And if you don't have a stable ID, the XPath that we got is not reliable. &lt;/p&gt;

&lt;p&gt;There are lots of web applications which are using dynamic IDs for some elements. &lt;/p&gt;

&lt;p&gt;An element with a dynamic ID is like a coffee shop which is changing its name every day. &lt;/p&gt;

&lt;p&gt;You know that the coffee shop was called iCoffee yesterday, but you have no idea what name is it going to have today. &lt;/p&gt;

&lt;p&gt;Telling your friend to meet you at iCoffee will be confusing.&lt;/p&gt;

&lt;p&gt;That's when we need to write our own XPath. &lt;/p&gt;

&lt;p&gt;Find out what are the stable attributes and characteristics of that element.&lt;/p&gt;

&lt;p&gt;Going back to the example with the coffee shop that has a different name. &lt;/p&gt;

&lt;p&gt;What is something that &lt;strong&gt;doesn't change&lt;/strong&gt; about it? &lt;/p&gt;

&lt;p&gt;Perhaps the &lt;strong&gt;location&lt;/strong&gt; and the fact that it's a &lt;strong&gt;coffee shop&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This means that you can tell your friend from out of town to meet you at the coffee shop from the West Shopping Mall.&lt;/p&gt;

&lt;p&gt;Let's take a look at our element and get the XPath of its parent:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdnuq77ou4k7rzoe2cakv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdnuq77ou4k7rzoe2cakv.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the XPath that we got for its parent:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;//*[&lt;a class="mentioned-user" href="https://dev.to/id"&gt;@id&lt;/a&gt;="signup-form"]/auto-check[1]/dl/dd&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is practically the address of the West Shopping Mall in our example. &lt;/p&gt;

&lt;p&gt;Now all we have to do add some details at the end. &lt;/p&gt;

&lt;p&gt;Our &lt;strong&gt;Username&lt;/strong&gt; element is an &lt;strong&gt;input&lt;/strong&gt; and it has the &lt;strong&gt;form-control&lt;/strong&gt; Class Name.&lt;/p&gt;

&lt;p&gt;This means that we need to append the following to the parent:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;/input[&lt;a class="mentioned-user" href="https://dev.to/class"&gt;@class&lt;/a&gt;="form-control"]&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And that part translates to: &lt;br&gt;
&lt;em&gt;Look in that parent for an input which has the form-control Class Name.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And the final XPath for our Username element will look like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;//*[&lt;a class="mentioned-user" href="https://dev.to/id"&gt;@id&lt;/a&gt;="signup-form"]/auto-check[1]/dl/dd/input[&lt;a class="mentioned-user" href="https://dev.to/class"&gt;@class&lt;/a&gt;="form-control"]&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Always verify your XPath in the Chrome console by hitting Ctrl + F and searching for it, you should see your element highlighted like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ad9h4r1ap7x2a0wteaq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ad9h4r1ap7x2a0wteaq.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Writing your own XPaths isn't so scary. You will encounter situations where your element might not have an ID, but it will have a certain reliable attribute which makes it unique.&lt;/p&gt;

&lt;p&gt;In that case, your XPath will look like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;//*[@attribute = "attribute_value"]&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can also write an XPath which locates the element by using only part of the value of the attribute: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;//*[contains(@attribute, "part_of_attribute_value")]&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example, our &lt;strong&gt;Username&lt;/strong&gt; element has the following attributes:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;aria-describedby="description_2822cb3d798c"&lt;/em&gt;&lt;br&gt;
&lt;em&gt;name = "user[login]"&lt;/em&gt; &lt;br&gt;
&lt;em&gt;autocapitalize = "off"&lt;/em&gt; &lt;br&gt;
&lt;em&gt;autofocus = "autofocus"&lt;/em&gt; &lt;br&gt;
&lt;em&gt;required = "required"&lt;/em&gt; &lt;br&gt;
&lt;em&gt;class = "form-control"&lt;/em&gt; &lt;br&gt;
&lt;em&gt;type = "text"&lt;/em&gt; &lt;br&gt;
&lt;em&gt;id = "user_login"&lt;/em&gt; &lt;br&gt;
&lt;em&gt;autocomplete = "off"&lt;/em&gt;&lt;br&gt;
&lt;em&gt;spellcheck = "false"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If we want to use the &lt;strong&gt;aria-describedby&lt;/strong&gt; attribute, this will be the XPath:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;//*[@aria-describedby = "description_2822cb3d798c"]&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're using &lt;strong&gt;&lt;a href="https://endtest.io" rel="noopener noreferrer"&gt;Endtest&lt;/a&gt;&lt;/strong&gt; instead of Selenium, their recorder will know how to automatically extract these custom XPaths. &lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;5) Find Element By CSS Selector&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;CSS Selector&lt;/strong&gt; locator type is similar to XPath.&lt;/p&gt;

&lt;p&gt;Some people actually claim that it's faster.&lt;/p&gt;

&lt;p&gt;Usually, a CSS Selector looks like this:&lt;br&gt;
body &amp;gt; div.application-main &amp;gt; main &amp;gt; div &amp;gt; div &lt;/p&gt;

&lt;p&gt;And we extract it in a similar way:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fja87x8hz59cricx7rpmm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fja87x8hz59cricx7rpmm.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case, we got the following CSS Selector: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;#user_login&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're familiar with CSS, you'll know that &lt;strong&gt;#&lt;/strong&gt; stands for &lt;strong&gt;ID&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The similarities with XPath don't stop here.&lt;/p&gt;

&lt;p&gt;If you have a stable ID, you shouldn't bother to use CSS Selector.&lt;/p&gt;

&lt;p&gt;And if you don't have a stable ID, the CSS Selector that we got is not reliable.&lt;/p&gt;

&lt;p&gt;The solution?&lt;/p&gt;

&lt;p&gt;To write our own custom CSS Selector.&lt;/p&gt;

&lt;p&gt;Let's start by extracting the CSS Selector for the parent of the &lt;strong&gt;Username&lt;/strong&gt; element:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcmd6lq1kwsh5t6a2224b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcmd6lq1kwsh5t6a2224b.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is what we get:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;#signup-form &amp;gt; auto-check:nth-child(4) &amp;gt; dl &amp;gt; dd&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now, just like we did for XPath, we need add some details at the end. &lt;/p&gt;

&lt;p&gt;In case you forgot, our &lt;strong&gt;Username&lt;/strong&gt; element is an &lt;strong&gt;input&lt;/strong&gt; and it has the &lt;strong&gt;form-control&lt;/strong&gt; Class Name.&lt;/p&gt;

&lt;p&gt;This means that we need to append the following to the parent:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&amp;gt; input.form-control&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And that part translates to: &lt;br&gt;
&lt;em&gt;Look in that parent for an input which has the form-control Class Name.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you're familiar with CSS, the dot stands for Class Name.&lt;/p&gt;

&lt;p&gt;And the final CSS Selector for our Username element will look like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;#signup-form &amp;gt; auto-check:nth-child(4) &amp;gt; dl &amp;gt; dd &amp;gt; input.form-control&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's not mandatory to add both the element type and the Class Name.&lt;/p&gt;

&lt;p&gt;You can just use one of them:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;#signup-form &amp;gt; auto-check:nth-child(4) &amp;gt; dl &amp;gt; dd &amp;gt; input&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;#signup-form &amp;gt; auto-check:nth-child(4) &amp;gt; dl &amp;gt; dd &amp;gt; .form-control&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Again, if you're using &lt;strong&gt;&lt;a href="https://endtest.io" rel="noopener noreferrer"&gt;Endtest&lt;/a&gt;&lt;/strong&gt; instead of Selenium, their recorder will know how to automatically extract these custom CSS Selectors. &lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;6) Find Element By Link Text&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Link Text&lt;/strong&gt; locator type only works for links.&lt;/p&gt;

&lt;p&gt;Your element is a Link if it has the following format:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq9xjzticpxwwqdcnsabw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq9xjzticpxwwqdcnsabw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;a&lt;/strong&gt; stands for Anchor.&lt;/p&gt;

&lt;p&gt;Since our &lt;strong&gt;Username&lt;/strong&gt; element is an input and not a link, we won't be able to locate it by using Link Text.&lt;/p&gt;

&lt;p&gt;It's worth remembering that the Link Text is only the text between the tags.&lt;/p&gt;

&lt;p&gt;In the case of the link from the screenshot, the Link Text is &lt;strong&gt;Enterprise&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgw2l8tv2gwi45u22kmlf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgw2l8tv2gwi45u22kmlf.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our Selenium code would look like this:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;enterprise_link = driver.find_element_by_link_text("Enterprise")&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;7) Find Element By Partial Link Text&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;As the name suggests, it's exactly like &lt;strong&gt;Link Text&lt;/strong&gt;, but with the difference that you only need to add part of the Link Text.&lt;/p&gt;

&lt;p&gt;And this would be our Selenium code:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;enterprise_link = driver.find_element_by_partial_link_text("Enterp")&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;8) Find Element By Tag Name&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;As we have seen from the previous examples, an element always has a tag. &lt;/p&gt;

&lt;p&gt;You can use the &lt;strong&gt;Tag Name&lt;/strong&gt; locator type if that's the only unique characteristic of the element that you can grab on to. &lt;/p&gt;

&lt;p&gt;Realistically speaking, I don't think you'll ever use this one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://endtest.io" rel="noopener noreferrer"&gt;Endtest&lt;/a&gt;&lt;/strong&gt; has an extra locator type, &lt;strong&gt;Text Inside&lt;/strong&gt;, similar to Partial Link Text, but it works for all types of elements.&lt;/p&gt;

&lt;p&gt;Even if your locators are reliable, you will encounter situations where your web application goes through a revamping and you'll consume time on keeping your tests in sync with your web applications.&lt;/p&gt;

&lt;p&gt;One option to avoid this situation is to use Machine Learning:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/t7Wa5mTP45Q"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>testing</category>
      <category>productivity</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Can you believe I made a test that can play Chess?</title>
      <dc:creator>Klaus</dc:creator>
      <pubDate>Fri, 31 May 2019 12:52:26 +0000</pubDate>
      <link>https://dev.to/endtest/can-you-believe-i-made-a-test-that-can-play-chess-1ced</link>
      <guid>https://dev.to/endtest/can-you-believe-i-made-a-test-that-can-play-chess-1ced</guid>
      <description>&lt;p&gt;I have been experimenting a lot with the &lt;a href="https://endtest.io"&gt;Endtest&lt;/a&gt; platform lately, since I'm helping them out with my testing expertise.&lt;/p&gt;

&lt;p&gt;Trying to find extreme scenarios that cannot be automated, I ended up trying to automate some tests for a &lt;a href="https://quickchess.net"&gt;Chess&lt;/a&gt; game. &lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/WZKG6adhu6g"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Needless to say, it went pretty well. &lt;/p&gt;

&lt;p&gt;As you can see, my test played a decent game. &lt;/p&gt;

&lt;p&gt;The assertions are checking if my movements were registered correctly.&lt;/p&gt;

&lt;p&gt;What made it easy is the fact that all the pieces and squares are actual HTML elements. &lt;/p&gt;

&lt;p&gt;If I was dealing with a &lt;a href="https://www.w3schools.com/html/html5_canvas.asp"&gt;HTML5 Canvas&lt;/a&gt; element, I would have needed to use the &lt;strong&gt;Click with Offset&lt;/strong&gt; action.&lt;/p&gt;

&lt;p&gt;I talked to them and sent them the video, ended up being posted on their YouTube channel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can you think of any site or scenario that is impossible to automate?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Would love to get some fresh ideas.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>testing</category>
      <category>webdev</category>
      <category>discuss</category>
    </item>
    <item>
      <title>10 Things You Didn't Know About Selenium</title>
      <dc:creator>Klaus</dc:creator>
      <pubDate>Wed, 29 May 2019 13:51:52 +0000</pubDate>
      <link>https://dev.to/endtest/10-things-you-didn-t-know-about-selenium-39eh</link>
      <guid>https://dev.to/endtest/10-things-you-didn-t-know-about-selenium-39eh</guid>
      <description>&lt;h3&gt;
  
  
  &lt;strong&gt;1) You can use Selenium to test Chrome Extensions.&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Those extensions are built with HTML, CSS and JavaScript, you just have to learn a few tricks in order to access the extension in the main viewport.&lt;br&gt;
I wrote a detailed &lt;a href="https://dev.to/razgandeanu/testing-chrome-extensions-with-selenium-491b"&gt;tutorial&lt;/a&gt; about it a few months ago.&lt;/p&gt;

&lt;p&gt;You can also test Chrome Extensions with &lt;a href="//https:/endtest.io"&gt;Endtest&lt;/a&gt;. &lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;2) Taking a screenshot of an element instead of the entire page.&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This one is tricky. &lt;br&gt;
By default, Selenium only allows you to take a screenshot of the entire viewport. &lt;br&gt;
You need to extract the coordinates and the size of your element and use them to crop it from a full page screenshot. &lt;/p&gt;

&lt;p&gt;I used &lt;a href="https://pillow.readthedocs.io"&gt;Pillow&lt;/a&gt; for the cropping part. 🤓&lt;/p&gt;

&lt;p&gt;&lt;em&gt;driver.save_screenshot('/Users/Klaus/Test/fullPageScreenshot.png')&lt;/em&gt;&lt;br&gt;
&lt;em&gt;myElement = driver.find_element_by_id("register")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;location = myElement.location&lt;/em&gt;&lt;br&gt;
&lt;em&gt;left = int(location['x'])&lt;/em&gt;&lt;br&gt;
&lt;em&gt;top = int(location['y'])&lt;/em&gt;&lt;br&gt;
&lt;em&gt;right = int(location['x']) + int(size['width'])&lt;/em&gt;&lt;br&gt;
&lt;em&gt;bottom = int(location['y']) + int(size['height'])&lt;/em&gt;&lt;br&gt;
&lt;em&gt;fullPageScreenshot = Image.open('/Users/Klaus/Test/fullPageScreenshot.png')&lt;/em&gt;&lt;br&gt;
&lt;em&gt;elementScreenshot = fullPageScreenshot.crop((left, top, right, bottom))&lt;/em&gt;&lt;br&gt;
&lt;em&gt;elementScreenshot.save('/Users/Klaus/Test/elementScreenshot.png')&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;3) Uploading a file in a test.&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A cool trick I learned from my friends at &lt;a href="https://endtest.io"&gt;Endtest&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When you upload a file on a site, a native window from the Operating System opens which allows you to select the file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MXbjNTcf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ck5zymf6ig5h0ohcyqgt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MXbjNTcf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ck5zymf6ig5h0ohcyqgt.png" alt=""&gt;&lt;/a&gt;&lt;br&gt;
After you select the file from that native window, the local path of the file is written in the input type="file" element.&lt;/p&gt;

&lt;p&gt;The problem here is that Selenium cannot interact with that native window. &lt;br&gt;
This means that it cannot select the file. &lt;/p&gt;

&lt;p&gt;That's why we need to skip that part and just write the local path for that file in the input type="file" element.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;fileInput = driver.find_element_by_id("upload_file")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;fileInput.send_keys('/Users/Klaus/Test/Instructions.pdf')&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Of course, that input type="file" element might be hidden and you would need to unhide with some JavaScript:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;jsCode = 'document.getElementByid("#upload_file").style.display="block"'&lt;/em&gt;&lt;br&gt;
&lt;em&gt;driver.execute_script(jsCode)&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;4) Clicking on a certain point inside an element.&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;By default, Selenium clicks in the center of an element. &lt;/p&gt;

&lt;p&gt;You might need more precision when dealing with a &lt;a href="https://www.w3schools.com/html/html5_canvas.asp"&gt;HTML5 Canvas&lt;/a&gt; element. &lt;/p&gt;

&lt;p&gt;We can use the ActionChains from Selenium to move to a certain point inside the element and perform a click there.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;canvas = driver.find_element_by_id("drawing_board")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;chain = ActionChains(driver).move_to_element_with_offset(canvas, X, Y)&lt;/em&gt;&lt;br&gt;
&lt;em&gt;chain.click()&lt;/em&gt;&lt;br&gt;
&lt;em&gt;chain.perform()&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That's right, you can use Selenium to play Chess online. ♟️&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;5) Reading the Page Source.&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If your site is using &lt;a href="https://www.w3schools.com/tags/tag_meta.asp"&gt;&lt;/a&gt; tags, you can easily check those with Selenium.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;pageSource = driver.page_source&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As you know,  tags are hidden and can only be seen in the page source.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;6) Performing a Drag and Drop.&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Once again, we're using the ActionChains from Selenium.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;target = driver.find_element_by_id('ball')&lt;/em&gt;&lt;br&gt;
&lt;em&gt;destination = driver.find_element_by_id('goal')&lt;/em&gt;&lt;br&gt;
&lt;em&gt;ActionChains(driver).drag_and_drop(target, destination).perform()&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Did we just score a goal with Selenium? ⚽️😱&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;7) Simulate a webcam and a microphone.&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Useful if you're running your tests on a machine from a cloud.&lt;br&gt;
Available only with the chromedriver.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rEDEyhNx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/95qbfh4qv6l8gqpyzad0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rEDEyhNx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/95qbfh4qv6l8gqpyzad0.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;options = webdriver.ChromeOptions()&lt;/em&gt;&lt;br&gt;
&lt;em&gt;options.add_argument("--use-fake-ui-for-media-stream")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;options.add_argument("--use-fake-device-for-media-stream")&lt;/em&gt;&lt;br&gt;
&lt;em&gt;driver = webdriver.Chrome(executable_path=chromedriver, chrome_options=options)&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;8) Using HTTP Basic Authentication.&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;That's the native window which is asking for credentials to access a site. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BuZE561x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/kcow15ktmw01jntr6grb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BuZE561x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/kcow15ktmw01jntr6grb.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can't write text in those inputs with the traditional &lt;em&gt;send_keys&lt;/em&gt; method, because that window is outside the viewport. &lt;/p&gt;

&lt;p&gt;The solution? &lt;/p&gt;

&lt;p&gt;Just add your username and password directly in the URL.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;driver.get('&lt;a href="http://username:password@example.com'"&gt;http://username:password@example.com'&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;9. Using Machine Learning to fix your tests.&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/t7Wa5mTP45Q"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;10. Using any attribute to locate an element.&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Selenium lets you locate an element by using one of the following:&lt;br&gt;
• ID&lt;br&gt;
• Name&lt;br&gt;
• Class Name&lt;br&gt;
• Link Text&lt;br&gt;
• Partial Link Text&lt;br&gt;
• Tag Name &lt;br&gt;
• CSS Selector&lt;br&gt;
• XPath&lt;/p&gt;

&lt;p&gt;But what happens when you have an element like this one?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NtRAv6_g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/wbol1ucy4za0oqkximuf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NtRAv6_g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/wbol1ucy4za0oqkximuf.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You need to get creative and write an XPath based on an attribute, like this:&lt;/p&gt;

&lt;p&gt;//*[@attribute = "attribute_value"] &lt;/p&gt;

&lt;p&gt;For our element, this results in the following:&lt;/p&gt;

&lt;p&gt;//*[@type = "submit"] &lt;/p&gt;

&lt;p&gt;You can also write an XPath which locates the element by using only part of the value of the attribute: &lt;/p&gt;

&lt;p&gt;//*[contains(@attribute, "part_of_attribute_value")] &lt;/p&gt;

&lt;p&gt;For our element, this results in the following:&lt;/p&gt;

&lt;p&gt;//*[contains(@type, "sub")] &lt;/p&gt;

</description>
      <category>testing</category>
      <category>productivity</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
