<?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: David Burns</title>
    <description>The latest articles on DEV Community by David Burns (@automatedtester).</description>
    <link>https://dev.to/automatedtester</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%2Fuser%2Fprofile_image%2F341729%2Fcffadb7e-763d-4421-b1ee-3d916d663989.jpeg</url>
      <title>DEV Community: David Burns</title>
      <link>https://dev.to/automatedtester</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/automatedtester"/>
    <language>en</language>
    <item>
      <title>Flakiness isn't from your test framework</title>
      <dc:creator>David Burns</dc:creator>
      <pubDate>Tue, 28 May 2024 10:18:20 +0000</pubDate>
      <link>https://dev.to/automatedtester/flakiness-isnt-from-your-test-framework-17pn</link>
      <guid>https://dev.to/automatedtester/flakiness-isnt-from-your-test-framework-17pn</guid>
      <description>&lt;p&gt;The other week I saw Filip Hric share &lt;a href="https://www.linkedin.com/feed/update/urn:li:activity:7193270830271762432/"&gt;a post&lt;/a&gt; from Gleb Bahmutov, ex-principal engineer for Cypress, explaining that the way cypress works and not using transport layers like playwright or WebDriver based frameworks makes its tests less flaky.&lt;/p&gt;

&lt;p&gt;That’s 100% not the reason your tests are flaky. I’m not going to lie, this shocked me that Gleb would say this as I’ve always thought of him as a good engineer after seeing his work on Cypress. The reason your tests are flaky is more down to how you interpret the UI and how the browser runs the code, or to put in a different way, you’re thinking about your synchronous steps of a test while they’re running in an asynchronous way. &lt;strong&gt;This mismatch leads to flakiness&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now add in different browsers interpreting the code in different ways leads to more flakiness. This is why some frameworks don’t want to or can’t support different browsers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Single threadedness of JavaScript
&lt;/h2&gt;

&lt;p&gt;Cypress runs in the page that’s being tested. That means Cypress is hemmed in by the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy"&gt;same-origin policy&lt;/a&gt;. It injects what it needs to the page. The problem is this means CPU has to swap in commands from different tasks. This &lt;em&gt;could&lt;/em&gt; lead to less flakiness but it’s because it’s running much slower. Since there is no guarantee of ordering of commands between tests and the front end, the reduced flakiness is pure chance.&lt;/p&gt;

&lt;p&gt;Selenium, when &lt;a href="https://twitter.com/hugs"&gt;Jason Huggins&lt;/a&gt; created it, used this technique for automating the browser and Selenium moved away from it when we merged with WebDriver. Hugs have been calling this out for ever. It’s also the reason why you can’t do basic things like trusted events, iframes, or navigating between different &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Origin"&gt;origins&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1177619507927490560-348" src="https://platform.twitter.com/embed/Tweet.html?id=1177619507927490560"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1177619507927490560-348');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1177619507927490560&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Driving the browser from inside to outside, where outside is your webpage, is always going to give you a more realistic testing experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Transport layers
&lt;/h2&gt;

&lt;p&gt;The transport layer for speaking to the browser doesn’t affect the flakiness. Its main benefit is scalability. If you need your tests to run in the same browser as the runner then you struggle to scale. Since Selenium’s main transport system is based off HTTP we know it’s highly scalable. Cypress tests are less scalable because it wanted to do everything on the browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  but what about CDP?
&lt;/h3&gt;

&lt;p&gt;What about it? It’s a chromium based protocol. Playwright uses it, Puppeteer uses it, and this might shock you, Selenium uses it. This is firstly how Edgedriver and chromedriver speak to the browser. So if you’ve used chromedriver at any point in the last 8+ years you’ve used CDP.  Selenium can also speaks directly to the browser using CDP for some commands. We see this with their network intercept API and logging APIs are examples. Now, webdriverio also supports WebDriver and puppeteer through these APIs. So if we follow &lt;a href="https://glebbahmutov.com/blog/cypress-vs-other-test-runners/"&gt;Gleb’s post&lt;/a&gt;, we need to move &lt;em&gt;everything&lt;/em&gt; down to playwright/puppeteer part of his diagram.&lt;/p&gt;

&lt;p&gt;The one downside to having to rely on CDP is you limited to chromium specific APIs. These are not stable by design which the Chromium team will tell you. It’s the reason why chromedriver/edgedriver needs to be updated with each browser release. Fortunately, &lt;a href="https://www.theautomatedtester.co.uk/blog/2023/selenium-mananger/"&gt;Selenium Manager can auto update&lt;/a&gt; your drivers for you without you needing to worry. If you're not using Selenium Manager you will have to update all your dependencies which you would have to do with Playwright or puppeteer. If you’re using the Selenium event driven APIs then you will have to update your selenium dependency.&lt;/p&gt;

&lt;p&gt;As mentioned, it does limit us to chromium specific APIs which is why Selenium is working with Google, Apple, Mozilla, and a few other little companies to bring about the new Webdriver-bidi spec. When WebDriver-BiDi is out to all browsers then the requirements for updating with the browser will drop like they did with Firefox and geckodriver.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://developer.chrome.com/blog/webdriver-bidi/"&gt;puppeteer team is supporting WebDriver-BiDi&lt;/a&gt;. A debug protocol is not the best for automation as it relies heavily on browser state. It’s great for debugging but not automation. Since this work is happening in the open, we are happy for the playwright and cypress team to come collaborate with us.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do we solve flakiness then?
&lt;/h2&gt;

&lt;p&gt;Auto-waiting, minimizing what your tests are doing, and root cause analysis of failures. Webdriver.io, Nightwatch, playwright, puppeteer, and cypress have the auto waiting. All at different levels. There is some opinions that differ on what should be waited for but they are aiming for the same end result.&lt;/p&gt;

&lt;p&gt;Selenium has had auto waiting in a minimal wait with the explicit and implicit waits. People can struggle with them. These waits are opinionated like the above. So... we're down to which opinions we like. So... if you're learning a tool for a CV... well it's just an opinion that's different. How to do web testing, and understanding it, that is the super power you need.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;As an aside, when I was at Mozilla, automattic came to us saying they wanted puppeteer support as they were dropping selenium because of flakiness... and then then the flakiness was still happening with puppeteer&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Flakiness has been around for a long time. &lt;a href="https://twitter.com/shs96c"&gt;Simon Stewart&lt;/a&gt; wrote a &lt;a href="https://testing.googleblog.com/2009/06/my-selenium-tests-arent-stable.html"&gt;good blog post about this problem 15 years ago&lt;/a&gt; and how to solve some of them. This is not a new problem and someone telling you their framework will solve it is lying.&lt;/p&gt;

&lt;p&gt;Unfortunately, there will still be some flakiness… and it’s not your fault.&lt;/p&gt;

&lt;h2&gt;
  
  
  Front end frameworks hate testers
&lt;/h2&gt;

&lt;p&gt;These frameworks make flakiness equal when it comes to testing.&lt;/p&gt;

&lt;p&gt;Browsers have had to put a lot of effort to improving the speed of rendering and painting to handle these because of the constant moving in and out of the DOM. These asynchronous changes to the DOM  the way your tests run. In selenium you’ll hit a &lt;code&gt;StaleElementReference&lt;/code&gt;. These are painful but auto waiting can solve it for you easily. Batteries included systems, like NightwatchJS, webdriverio, playwright, and cypress try make how this works opaque to the end user.&lt;/p&gt;

&lt;h3&gt;
  
  
  Asynchronocity is hard
&lt;/h3&gt;

&lt;p&gt;As I alluded to above, we don’t think of tests in the same way we think of rendering front end tests. When we’re wanting to take data off a server and render it, it’s all happening asynchronously due to how JavaScript and fetch APIs work. The move to server side rendering again is not going to solve this either… it’s just moving the heavy lifting around. Yes with promises we can write code that looks synchronous but that’s just for where that bit of code is. A slow response from a server can impact our tests. Having your tests and front end competing in the same thread won’t make your tests less flaky other than by sheer luck.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finally… work in the same world as your users
&lt;/h2&gt;

&lt;p&gt;So is there any benefit to running your tests in Electron? Well… how many of your users use your site with electron? Probably the same amount as would use playwright-Firefox or playwright-WebKit. It’s a number that is very close to 0.&lt;/p&gt;

&lt;p&gt;I’ve talked about this many times about having your tests work. It’s important to have a number of tests running in the environments where our users are. I’ve got examples in my talk from last year. Different environments, like mobile versus desktop, can also lead to different reasons for flakiness.&lt;/p&gt;

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

&lt;p&gt;So… when picking a framework, pick one that works well for you. It should be able to do a &lt;a href="https://www.theautomatedtester.co.uk/blog/2023/the-login-test/"&gt;Login Test&lt;/a&gt; easily. If it can’t then it shouldn’t be used.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>testing</category>
    </item>
    <item>
      <title>Engineering culture is hard to make but easy to destroy</title>
      <dc:creator>David Burns</dc:creator>
      <pubDate>Mon, 21 Nov 2022 11:58:41 +0000</pubDate>
      <link>https://dev.to/automatedtester/engineering-culture-is-hard-to-make-but-easy-to-destroy-23m9</link>
      <guid>https://dev.to/automatedtester/engineering-culture-is-hard-to-make-but-easy-to-destroy-23m9</guid>
      <description>&lt;p&gt;Like most people, I have been watching, with utter despair, the downfall of Twitter. Twitter, the community, has been a bit of a cesspool in general but there are some really great micro communities that help each other.&lt;/p&gt;

&lt;p&gt;I know I have met amazing people on there and from there cultivated great friendships.&lt;/p&gt;

&lt;p&gt;The one thing that has shocked me with Elon Musk, is not how he said he was going to down size the company. He told people that at the beginning. It's the callousness of all his actions!&lt;/p&gt;

&lt;h2&gt;
  
  
  Bullying is never ok
&lt;/h2&gt;

&lt;p&gt;Anyone who has seen the news reports from &lt;a href="https://labortribune.com/tesla-found-guilty-of-union-busting/"&gt;Union Busting at Tesla&lt;/a&gt; to issues with Self-driving Cars(now a class action lawsuit) to him seemingly breaking WARN Act in California, know Musk has little regard for laws around him.&lt;/p&gt;

&lt;p&gt;This has lead to, at least if rumours are true and what we're seeing at Twitter suggests they are, a constant bad engineering culture within all Musk companies. Bullying and Harassment.&lt;/p&gt;

&lt;p&gt;Now, at this point I can foresee Musk supporters thinking "Well you're not a billionaire so why should we listen to you?". You don't need to listen/read anything I put out there. No doubt that Musk has been a shrewd investor, but the concepts and successes are built on the people doing the hard work. If my family had also been able to exploit South Africans during Apartheid, I too would be significantly wealthy.&lt;/p&gt;

&lt;p&gt;But being a shrewd investor doesn't mean it's ok to bully or harass folks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a healthy culture
&lt;/h2&gt;

&lt;p&gt;A healthy culture is a productive culture in the same way a healthy population will be a prosperous nation. When people feel they can make mistakes safely they are going to learn and build and grow with you. It's one of the main reasons in the tech world we have moved to blameless retrospectives.&lt;/p&gt;

&lt;p&gt;One thing that is true, and underrated, is "Every hire will impact your culture". If you go for a group of Chads, or mix it up with people from different backgrounds, you will have a different culture. I have worked on teams where there were 6 of us (3 David's and literally no women). I learned more and grew more as an engineering leader by having different people around me.&lt;/p&gt;

&lt;h3&gt;
  
  
  Words matter
&lt;/h3&gt;

&lt;p&gt;Words matter, and the more multinational a company is, the more important words can be. How you speak to people is going to show them how they can interact with you. I know when I speak to certain parts of the world I need to make sure that if someone calls me sir that I remind them that I am not knighted and they should just call me David.&lt;/p&gt;

&lt;p&gt;Why? Because if they fail they are likely to feel that they can't speak to me. I also remind them that fail stands for &lt;em&gt;First Attempt In Learning&lt;/em&gt;. Calling people by their prefered name, and definitely not their Dead Name, means they are likely to listen to you. It's really the little things.&lt;/p&gt;

&lt;h3&gt;
  
  
  Leaders need to be at the front
&lt;/h3&gt;

&lt;p&gt;Leaders showing people how to do things from the front, even if it makes you feel "weak", creates empathy between you and your team. It's long known that facism is beaten by empathy. Empathy is not a weakness, it's a super power. It also will help them feel like they can challenge you if you are wrong. Musk has shown that if you challenge him you will get fired. He is now surrounded by sycophants. People won't challenge him and it's leading to him looking like the emporer with his new clothes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Culture can be destroyed in an instant
&lt;/h2&gt;

&lt;p&gt;One thing that I learned back in my Mozilla days was that culture can be destroyed by poorly chosen words by leaders or&lt;br&gt;
poorly chosen actions. The actions of leaders can hurt people. If you want amazing products you need diverse teams. It's important to It takes time to build a culture that people want to be part of, that allows failure and learning. Trust can takes weeks to months to years to craft. Ask any manager who does 1:1s...&lt;/p&gt;

&lt;p&gt;Building a rapport that allows people to be their best within a team so you can have a group of people at their best forming the best team takes time. You can't just force culture on people, especially since each person can change the culture in the group. It needs to get there through discussion and tradeoffs.&lt;/p&gt;

&lt;p&gt;It takes time to build world class engineering and a good set of leaders who can handle the tradeoffs that teams need. Build out what we need when we need it. Musk clearly doesn't have that skill. I bet there are a couple good managers at his companies that can help deliver things but it's clear from his actions it's not him.&lt;/p&gt;

&lt;p&gt;It's going to impact other companies. Twitter, Telsa, and SpaceX will feel it soon in their recruitment as that dries up quickly with people refusing to work there because of the actions of the CEO. I definitely wouldn't want to work there!&lt;/p&gt;

&lt;h2&gt;
  
  
  Finally
&lt;/h2&gt;

&lt;p&gt;And finally, you need to read &lt;a href="https://matt-rickard.com/chestertons-fence"&gt;Chesterton's Fence&lt;/a&gt; and think about all the things that Musk is doing. It will hopefully frame why a lot of well respected people in their field are utterly shocked by the actions to people and systems happening in Twitter!&lt;/p&gt;

</description>
      <category>engineering</category>
      <category>team</category>
      <category>management</category>
    </item>
    <item>
      <title>I am on Twitch - Come work on Selenium with me!</title>
      <dc:creator>David Burns</dc:creator>
      <pubDate>Tue, 26 Jan 2021 08:36:34 +0000</pubDate>
      <link>https://dev.to/automatedtester/i-am-on-twitch-come-work-on-selenium-with-me-3lk6</link>
      <guid>https://dev.to/automatedtester/i-am-on-twitch-come-work-on-selenium-with-me-3lk6</guid>
      <description>&lt;p&gt;At the end of 2020, I wanted to try something new, well new for the Selenium community. I created a new &lt;a href="https://twitch.tv/automatedtester"&gt;Twitch channel&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;The main reason is that I wanted to show people that working on Selenium is not scary. You don't need to be a "rockstar" engineer. Actually, Rockstars are actively discouraged since they normally just trash hotel rooms.&lt;/p&gt;

&lt;h2&gt;
  
  
  What have I done so far?
&lt;/h2&gt;

&lt;p&gt;I have shown people around the codebase. With Selenium being a &lt;a href="https://trunkbaseddevelopment.com/monorepos/"&gt;monorepo&lt;/a&gt; which we do &lt;a href="https://trunkbaseddevelopment.com/"&gt;Trunk Based Development&lt;/a&gt;. This can seem scary to some people seeing the code for the first time. I showed that it's not scary!&lt;/p&gt;

&lt;p&gt;I also showed people how they can contribute to the &lt;a href="https://github.com/seleniumhq/seleniumhq.github.io"&gt;Selenium Documentation&lt;/a&gt;. Documentation is how a number of Selenium Core contributors got into the project as it is a definite pay it forward system, making sure that future Selenium users&lt;br&gt;
have correct working examples.&lt;/p&gt;

&lt;p&gt;And last week was about starting to remove all the python 2 specific code from the python part of the tree. This is not complete and, this week, I hope to work on it a bit more. I will be leaving the code base littered with TODO if anyone wanted to contribute.&lt;/p&gt;

&lt;h2&gt;
  
  
  When
&lt;/h2&gt;

&lt;p&gt;At the moment there is a session every Thursday at 2 PM GMT. Hopefully, as the UK comes out of lockdown, I will be able to add a few more sessions during a week. If you &lt;a href="https://www.twitch.tv/automatedtester/"&gt;subscribe to the channel&lt;/a&gt; you will be updated as sessions change and be notified when a session has started. So please do subscribe! If you miss a session they are stored on Twitch for a couple weeks so you can always catch up later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future Sessions
&lt;/h2&gt;

&lt;p&gt;As we go through the year if you have ideas of things you want to see in a session, please let me know. My DMs on &lt;a href="https://twitter.com/automatedtester"&gt;Twitter&lt;/a&gt; are open or feel free to add something to a session chat.&lt;/p&gt;

&lt;p&gt;Originally posted on &lt;a href="https://www.theautomatedtester.co.uk/blog/2021/i-am-on-twitch/"&gt;my blog&lt;/a&gt;&lt;/p&gt;

</description>
      <category>selenium</category>
      <category>twitch</category>
    </item>
    <item>
      <title>Browser Testing and Tools WG Meeting @ TPAC 2020</title>
      <dc:creator>David Burns</dc:creator>
      <pubDate>Mon, 02 Nov 2020 12:03:38 +0000</pubDate>
      <link>https://dev.to/automatedtester/browser-testing-and-tools-wg-meeting-tpac-2020-2332</link>
      <guid>https://dev.to/automatedtester/browser-testing-and-tools-wg-meeting-tpac-2020-2332</guid>
      <description>&lt;p&gt;It's that time of the year where working groups from the W3C meet up to discuss the various standards that&lt;br&gt;
are being worked on.&lt;/p&gt;

&lt;p&gt;Within the Browser Testing and Tools Working Group, there are 2 different standards.&lt;/p&gt;

&lt;p&gt;We have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://w3c.github.io/webdriver/"&gt;WebDriver&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://w3c.github.io/webdriver-bidi"&gt;WebDriver-Bidi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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&gt;

&lt;p&gt;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"&gt;WebDriver-Bidi&lt;/a&gt; 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't guarantee that.&lt;/p&gt;

&lt;p&gt;If you'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"&gt;W3 Wiki&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>standards</category>
      <category>testing</category>
      <category>selenium</category>
    </item>
    <item>
      <title>How Selenium Works: Episode 7 - Driver Executables</title>
      <dc:creator>David Burns</dc:creator>
      <pubDate>Fri, 08 May 2020 10:52:09 +0000</pubDate>
      <link>https://dev.to/automatedtester/how-selenium-works-episode-7-driver-executables-3m60</link>
      <guid>https://dev.to/automatedtester/how-selenium-works-episode-7-driver-executables-3m60</guid>
      <description>&lt;p&gt;So this episode is going to be slightly different to previous episodes as this question came up this week. Why do browser vendors and the Selenium Project ship a driver executable? And Why do I need to update it with every browser release?&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do I need to download something?
&lt;/h2&gt;

&lt;p&gt;This is one of the biggest pain points I have seen people struggle with when using Selenium. The majority of the people who struggle are those who do not have a lot of experience programming. So why do we download this executable?&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://dev.to/automatedtester/how-selenium-works-episode-1-transportation-26de"&gt;Episode 1&lt;/a&gt; I mentioned Selenium under the hood speaks a &lt;a href="https://dev.to/automatedtester/how-selenium-works-episode-1-transportation-26de#http-and-rest-ish-really"&gt;REST-ish API&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The driver you are downloading is an HTTP server for the client libraries to be able to speak to.&lt;/p&gt;

&lt;h2&gt;
  
  
  So... Why not just get the client bindings to speak whatever is native to the browser?
&lt;/h2&gt;

&lt;p&gt;Unfortunately, as I mentioned in &lt;a href="https://dev.to/automatedtester/how-selenium-works-episode-1-transportation-26de"&gt;Episode 1&lt;/a&gt;, doing that increases the amount of work each binding maintainer needs to do and potentially limits who can write the bindings.&lt;/p&gt;

&lt;p&gt;It also means any setup required for the browser needs to be done by the bindings. If you're using a Chromium-based browser or Firefox, the bindings will need to know where to find the browser executable normally, as well as make sure the profile directory is created properly. It also puts the onus of fixing any breaking changes the browser vendors do to their startup setups on to each of the binding maintainers.&lt;/p&gt;

&lt;p&gt;Trust me, the Selenium Project used to do that and every browser release day meant a mad scramble. We would start running tests in an attempt to make sure nothing was broken. We would fix the problems and then release. This herculean effort by core contributors meant we were limited in adding new features.&lt;/p&gt;

&lt;p&gt;Not having to scramble and making sure it was simple for client binding maintainers to keep up to date was a great push for creating the &lt;a href="https://w3c.github.io/webdriver/"&gt;WebDriver Specification&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about automatic downloads from the Selenium Project?
&lt;/h2&gt;

&lt;p&gt;Well... This is something we have wanted to implement in the past but we haven't had time. Fortunately, there have been other projects that have come along and made this work easier. In the future, we are likely to try to incorporate one of these projects or we might look to see about implementing something ourselves. &lt;/p&gt;

&lt;p&gt;This will be something we will try look into once we have shipped Selenium 4.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>selenium</category>
      <category>webdriver</category>
      <category>browsers</category>
    </item>
    <item>
      <title>How Selenium Works: Episode 6 - sendKeys</title>
      <dc:creator>David Burns</dc:creator>
      <pubDate>Mon, 20 Apr 2020 08:12:06 +0000</pubDate>
      <link>https://dev.to/automatedtester/how-selenium-works-episode-6-sendkeys-556m</link>
      <guid>https://dev.to/automatedtester/how-selenium-works-episode-6-sendkeys-556m</guid>
      <description>&lt;p&gt;After an interaction on the last weekend of January 2020, on a Selenium Issue where someone said “why can’t you just…” after I explained the issue I thought that I would start explaining commands in Selenium WebDriver and why we landed on the design that we have today.&lt;/p&gt;

&lt;p&gt;I will repeat this on every page of the series but a lot, an annoying amount sometimes, of thinking goes into how every little bit of Selenium works. &lt;/p&gt;

&lt;p&gt;In this episode, we are going to look at what goes into clicking. For simplicity, we are only going to be looking at the work that goes into doing &lt;code&gt;element.send_key("a string")&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  You have an element you want to send some text, now what?
&lt;/h2&gt;

&lt;p&gt;So you have &lt;a href="https://dev.to/automatedtester/how-selenium-works-episode-4-finding-elements-o18"&gt;found an element&lt;/a&gt; and you need to send text to it. Selenium will go through the following steps before it even sends any text.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check Element is still on the page.
&lt;/h3&gt;

&lt;p&gt;When we were &lt;a href="https://dev.to/automatedtester/how-selenium-works-episode-4-finding-elements-o18#what-happens-when-it-finds-the-element"&gt;finding an element&lt;/a&gt; the browser would have returned a representation of that element. All subsequent calls to that element need to be checked that the element is still on the page. If it is not you will get a &lt;code&gt;StaleElementReferenceException&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check the element is visible
&lt;/h3&gt;

&lt;p&gt;Once we know the element is still on the page we need to make sure that the element &lt;a href="https://dev.to/automatedtester/how-selenium-works-episode-3-isdisplayed-10p4"&gt;is displayed&lt;/a&gt;. This is important as we would never expect a user to click on an element that is not visible. Since a user would never click there we need to make sure that Selenium can't click here too. If it is not displayed you will receive an &lt;code&gt;ElementNotVisibleException&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scroll to the element
&lt;/h3&gt;

&lt;p&gt;Next, we need to make sure that we can scroll to the element. To have all the events fire properly we are going to need to have the element in the &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Viewport"&gt;viewport&lt;/a&gt;. If the element is not in the viewport after trying to scroll to it, the browser will return an &lt;code&gt;ElementNotInteractableException&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check if the element is interactable
&lt;/h3&gt;

&lt;p&gt;The browser will now check if the element that will receive our text can receive it. For example, we will look if the element might be &lt;code&gt;disabled&lt;/code&gt;. If it looks like the element can't receive the text, the browser will throw an &lt;code&gt;ElementNotInteractableException&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Process Text String
&lt;/h3&gt;

&lt;p&gt;The next step is we need to process the string that has come in and split it according to &lt;a href="http://www.unicode.org/reports/tr29/"&gt;grapheme text clusters&lt;/a&gt;. We do this as Selenium has assigned some values in the &lt;a href="https://en.wikipedia.org/wiki/Private_Use_Areas"&gt;unicode private use area&lt;/a&gt; or PUA for some of the keys. Below is a sample&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="n"&gt;TAB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;\&lt;/span&gt;&lt;span class="se"&gt;ue004&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;CLEAR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;\&lt;/span&gt;&lt;span class="se"&gt;ue005&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;RETURN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;\&lt;/span&gt;&lt;span class="se"&gt;ue006&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;ENTER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;\&lt;/span&gt;&lt;span class="se"&gt;ue007&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;SHIFT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;\&lt;/span&gt;&lt;span class="se"&gt;ue008&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This allows people to send through combinations of keys like below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium.webdriver.common.keys&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Keys&lt;/span&gt;
    &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"I"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;Keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SPACE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"love "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;Keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHIFT&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"cheese"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# This writes "I love CHEESE"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Firing some events off
&lt;/h3&gt;

&lt;p&gt;Now we're ready to fire off some events. The browser will have gotten the string, so in the case above it would have received &lt;code&gt;I\ue00dlove \ue008cheese&lt;/code&gt;. The browser will split this into an array and process each character. When it hits one of the PUA it will have logic that needs to apply. For example, with the &lt;code&gt;Keys.SHIFT&lt;/code&gt; it will set the shift property on characters that follow.&lt;/p&gt;

&lt;p&gt;It will fire off a list of events into the event loop so that it will come across as a &lt;a href="https://dom.spec.whatwg.org/#dom-event-istrusted"&gt;trusted event&lt;/a&gt;. And when done, it will return to the Selenium script.&lt;/p&gt;

&lt;h3&gt;
  
  
  What about navigation?
&lt;/h3&gt;

&lt;p&gt;We need to tell the browser to watch for navigation happening thanks to the click. If a click does cause a navigation we apply the same logic if we were &lt;a href="https://dev.to/automatedtester/how-selenium-works-episode-2-navigation-48ij"&gt;navigating&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exceptions
&lt;/h3&gt;

&lt;h4&gt;
  
  
  File Inputs
&lt;/h4&gt;

&lt;p&gt;There is one element that will be an exception and that is the &lt;code&gt;&amp;lt;input type=file&amp;gt;&lt;/code&gt; element. When this element is being interacted with the browser will try to check if the string being passed in is a path to a file. If it is not, the browser will error and pass that back to the Selenium script. When using Selenium Grid, Selenium will encode the file you want to upload as a base64 string, send it through the grid, and then let the grid update the file path that will be used.&lt;/p&gt;

&lt;p&gt;Selenium will also try to ignore some of the visibility checks. This is because File inputs can't be styled so people do CSS tricks to have a nicer looking element on the page and hide the actual &lt;code&gt;&amp;lt;input type=file&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  IME Keyboards
&lt;/h4&gt;

&lt;p&gt;Send keys do not engage the IME keyboards on the operating system. Selenium assumes a US Keyboard for everything. Fortunately, Send Keys does allow you to send through Unicode characters if you need to type kanji or other languages that would require an IME keyboard. You might not get any special events from the IME keyboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;p&gt;You can read the &lt;a href="https://w3c.github.io/webdriver/#element-send-keys"&gt;WebDriver Specification&lt;/a&gt; for more details on what the browser does for send keys.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>automation</category>
      <category>selenium</category>
      <category>browsers</category>
    </item>
    <item>
      <title>How Selenium Works: Episode 5 - clicking</title>
      <dc:creator>David Burns</dc:creator>
      <pubDate>Tue, 31 Mar 2020 08:25:06 +0000</pubDate>
      <link>https://dev.to/automatedtester/how-selenium-works-episode-5-clicking-3m55</link>
      <guid>https://dev.to/automatedtester/how-selenium-works-episode-5-clicking-3m55</guid>
      <description>&lt;p&gt;After an interaction on the last weekend of January 2020, on a Selenium Issue where someone said “why can’t you just…” after I explained the issue I thought that I would start explaining commands in Selenium WebDriver and why we landed on the design that we have today.&lt;/p&gt;

&lt;p&gt;I will repeat this on every page of the series but a lot, an annoying amount sometimes, of thinking goes into how every little bit of Selenium works. &lt;/p&gt;

&lt;p&gt;In this episode, we are going to look at what goes into clicking. For simplicity, we are only going to be looking at the work that goes into doing &lt;code&gt;element.click()&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  You have an element you want to click, now what?
&lt;/h2&gt;

&lt;p&gt;So you have &lt;a href="https://dev.to/automatedtester/how-selenium-works-episode-4-finding-elements-o18"&gt;found an element&lt;/a&gt; and you need to click on it. Selenium will go through the following steps before it even does the click.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check Element is still on the page.
&lt;/h3&gt;

&lt;p&gt;When we were &lt;a href="https://dev.to/automatedtester/how-selenium-works-episode-4-finding-elements-o18#what-happens-when-it-finds-the-element"&gt;finding an element&lt;/a&gt; the browser would have returned a representation of that element. All subsequent calls to that element need to be checked that the element is still on the page. If it is not you will get a &lt;code&gt;StaleElementReferenceException&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check the element is visible
&lt;/h3&gt;

&lt;p&gt;Once we know the element is still on the page we need to make sure that the element &lt;a href="https://dev.to/automatedtester/how-selenium-works-episode-3-isdisplayed-10p4"&gt;is displayed&lt;/a&gt;. This is important as we would never expect a user to click on an element that is not visible. Since a user would never click there we need to make sure that Selenium can't click here too. If it is not displayed you will receive an &lt;code&gt;ElementNotVisibleException&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scroll to the element
&lt;/h3&gt;

&lt;p&gt;Next, we need to make sure that we can scroll to the element. To have all the events fire properly we are going to need to have the element in the &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Viewport"&gt;viewport&lt;/a&gt;. If the element is not in the viewport after trying to scroll to it, the browser will return a &lt;code&gt;ElementNotInteractableException&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check if the element is interactable
&lt;/h3&gt;

&lt;p&gt;The browser will now check if the element that will receive clicks in the area that we're telling it is the same element as we have passed in. If it looks like it's not the element that will receive the click the browser will throw a &lt;code&gt;ElementClickInterceptedException&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Firing some events off
&lt;/h3&gt;

&lt;p&gt;Now we're ready to fire off some events. We have a special case for &lt;code&gt;&amp;lt;option&amp;gt;&lt;/code&gt; to make sure that it's parent element that receives the events.&lt;/p&gt;

&lt;p&gt;We then calculate the centre of the element and start sending the events. You can read which events we send in the &lt;a href="https://w3c.github.io/webdriver/#element-click"&gt;WebDriver Specification&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What about navigation?
&lt;/h3&gt;

&lt;p&gt;We need to tell the browser to watch for navigation happening thanks to the click. If a click does cause a navigation we apply the same logic if we were &lt;a href="https://dev.to/automatedtester/how-selenium-works-episode-2-navigation-48ij"&gt;navigating&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;p&gt;You can read the &lt;a href="https://w3c.github.io/webdriver/#element-click"&gt;WebDriver Specification&lt;/a&gt; for more details&lt;/p&gt;

</description>
      <category>testing</category>
      <category>browsers</category>
      <category>automation</category>
      <category>selenium</category>
    </item>
    <item>
      <title>How Selenium Works: Episode 4 - Finding Elements</title>
      <dc:creator>David Burns</dc:creator>
      <pubDate>Tue, 17 Mar 2020 09:17:57 +0000</pubDate>
      <link>https://dev.to/automatedtester/how-selenium-works-episode-4-finding-elements-o18</link>
      <guid>https://dev.to/automatedtester/how-selenium-works-episode-4-finding-elements-o18</guid>
      <description>&lt;p&gt;After an interaction on the last weekend of January 2020, on a Selenium Issue where someone said “why can’t you just…” after I explained the issue I thought that I would start explaining commands in Selenium WebDriver and why we landed on the design that we have today.&lt;/p&gt;

&lt;p&gt;I will repeat this on every page of the series but a lot, an annoying amount sometimes, of thinking goes into how every little bit of Selenium works. &lt;/p&gt;

&lt;p&gt;In this episode we are going to look at how &lt;code&gt;findElement&lt;/code&gt; works. We need to be able to find elements before we can interact with them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding an element is easy right?
&lt;/h2&gt;

&lt;p&gt;Well, yes if people designed their applications for testability over anything else! Unfortunately we live in a world where most of the time people think about quality and testing as an after thought.&lt;/p&gt;

&lt;p&gt;Anyway... so let's look at the different ways we can look them up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Search Types
&lt;/h3&gt;

&lt;p&gt;This part is simple, Selenium offers the same methods for searching as you can find when interacting with the DOM with JavaScript. If we can look up things via &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll"&gt;&lt;code&gt;document.querySelectorAll(aQuery);&lt;/code&gt;&lt;/a&gt; then it will be searchable via &lt;code&gt;find_element&lt;/code&gt; or &lt;code&gt;find_elements&lt;/code&gt;. This is searchable from the &lt;code&gt;WebDriver&lt;/code&gt; object or from the &lt;code&gt;WebElement&lt;/code&gt; object. If you do &lt;code&gt;element.find_element(...)&lt;/code&gt; that is equalivent to doing &lt;code&gt;element.querySelectorAll(aQuery)&lt;/code&gt; which sets the starting point, or the root, for searching from that element.&lt;/p&gt;

&lt;p&gt;Below is an example of how to use &lt;code&gt;find_element&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium.webdriver.common.by&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;By&lt;/span&gt;

&lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Firefox&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://www.theautomatedtester.co.uk"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"someID"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CSS_SELECTOR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"#someID"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_elements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CSS_SELECTOR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"#someID"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"someName"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_elements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"someName"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CLASS_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"someName"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_elements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CLASS_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"someName"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TAG_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"someName"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_elements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TAG_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"someName"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can also look up elements on the page by &lt;a href="https://developer.mozilla.org/en-US/docs/Web/XPath"&gt;XPATH&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We can do the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium.webdriver.common.by&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;By&lt;/span&gt;

&lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Firefox&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://www.theautomatedtester.co.uk"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;XPATH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"//li"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can also look up links based on the visible text. Visible text uses the &lt;a href="https://dev.to%7B%7B&amp;lt;%20ref%20"&gt;}}"&amp;gt;&lt;code&gt;isDisplayed&lt;/code&gt; algorithm&lt;/a&gt; to work out what people can and can't read. Selenium will collect all the &lt;code&gt;&amp;lt;a&amp;gt;&amp;lt;/a&amp;gt;&lt;/code&gt; tags on the page, get the visible text, and then find the first element that has that text.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium.webdriver.common.by&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;By&lt;/span&gt;

&lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Firefox&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://www.theautomatedtester.co.uk"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LINK_TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"some text"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PARTIAL_LINK_TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  What happens when it finds the element?
&lt;/h2&gt;

&lt;p&gt;When we are able to find an element we keep track of it in a Map. The Map will contain a representation of a element using &lt;a href="https://en.wikipedia.org/wiki/Universally_unique_identifier"&gt;uuid&lt;/a&gt;. The map allows us to look up elements when we get them back from a Selenium test and make sure that element is actually &lt;a href="https://dom.spec.whatwg.org/#connected"&gt;connected&lt;/a&gt; to the DOM. If the element is not connected to the DOM and you try use it you will get a &lt;a href="https://w3c.github.io/webdriver/#dfn-stale-element-reference"&gt;&lt;code&gt;StaleElementReferenceException&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  and when it doesn't find the element or elements
&lt;/h2&gt;

&lt;p&gt;There are 2 things that can happen. &lt;/p&gt;

&lt;p&gt;If you look for only 1 element you will get an exception like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium.common.exceptions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;NoSuchElementException&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium.webdriver.common.by&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;By&lt;/span&gt;

&lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Firefox&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://www.theautomatedtester.co.uk"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LINK_TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"some text"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;NoSuchElementException&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you are looking for more than 1 element you will get an empty list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium.common.exceptions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;NoSuchElementException&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium.webdriver.common.by&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;By&lt;/span&gt;

&lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Firefox&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://www.theautomatedtester.co.uk"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_elements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CSS_SELECTOR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"myShadowElements"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Coming Soon: Relative locators
&lt;/h2&gt;

&lt;p&gt;These allow you to search for elements on the page by their relative position to another. For example you can find the element that is above and to the left of another element. See below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium.common.exceptions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;NoSuchElementException&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium.webdriver.common.by&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;By&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium.webdriver.support.relative_locator&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;with_tag_name&lt;/span&gt;

&lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Firefox&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://www.theautomatedtester.co.uk"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_elements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;with_tag_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"td"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;above&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"center"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;\
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_right_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"second"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;p&gt;You can read further in the &lt;a href="https://w3c.github.io/webdriver/#element-retrieval"&gt;Element Retrieval&lt;/a&gt; section of the &lt;a href="https://w3c.github.io/webdriver/"&gt;WebDriver Specification&lt;/a&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>automation</category>
      <category>browsers</category>
    </item>
    <item>
      <title>How Selenium Works: Episode 3 - isDisplayed</title>
      <dc:creator>David Burns</dc:creator>
      <pubDate>Wed, 11 Mar 2020 15:13:12 +0000</pubDate>
      <link>https://dev.to/automatedtester/how-selenium-works-episode-3-isdisplayed-10p4</link>
      <guid>https://dev.to/automatedtester/how-selenium-works-episode-3-isdisplayed-10p4</guid>
      <description>&lt;p&gt;After an interaction on the last weekend of January 2020, on a Selenium Issue where someone said “why can’t you just…” after I explained the issue I thought that I would start explaining commands in Selenium WebDriver and why we landed on the design that we have today.&lt;/p&gt;

&lt;p&gt;I will repeat this on every page of the series but a lot, an annoying amount sometimes, of thinking goes into how every little bit of Selenium works. &lt;/p&gt;

&lt;p&gt;In this episode we are going to look at the vast amount of work that goes into &lt;code&gt;isDisplayed()&lt;/code&gt;. This work is used in interaction commands so it is good to get an understanding of how this all works and how other commands use it. From a technical point of view, this is my favourite command and how it works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do we care if it is "displayed"?
&lt;/h2&gt;

&lt;p&gt;So, let's start with understanding why we would even want to care if the element is displayed or not. &lt;/p&gt;

&lt;p&gt;Firstly, testing is one the biggest use cases for Selenium so when people do an interaction on the page. Unfortunately, web pages are designed for showing information and not necessarily designed for interactive web pages. As we move to a more interactive web we needed a tool that could at least try workout if elements are visible. &lt;/p&gt;

&lt;p&gt;There are two main cases that we will try see if an element is visible. When we call the &lt;code&gt;element.is_displayed()&lt;/code&gt; for looking at an element and when we do interactions.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;NOTE&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Selenium has two type of commands when it comes to interactions. The methods found on &lt;code&gt;WebElement&lt;/code&gt; are of the "do what I mean" style: selenium tries to do make what you intended to happen when you &lt;code&gt;type&lt;/code&gt; or &lt;code&gt;click&lt;/code&gt;. The methods associated with &lt;code&gt;Actions&lt;/code&gt; are of the "do what I say" style --- these commands will do exactly what you tell them to, without attempting to interpret what you're actually trying to do.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How does it work?
&lt;/h2&gt;

&lt;p&gt;First of all, we need to understand that &lt;code&gt;element.is_displayed()&lt;/code&gt; needs to work without having to make the page scroll. This is important as we don't want to be moving the page unnecessarily.&lt;/p&gt;

&lt;p&gt;From there we need to have a look at the element. We need to start looking at the CSS that is on the element. &lt;/p&gt;

&lt;p&gt;First, let's see if the element would still be part of the accessibility tree. We don't look in the accessibility tree, we just look at some scenarios where they won't be there and they won't influence any positioning of elements on the page. We don't look in the accessibility tree as this can be an extremely expensive operation in the browser. &lt;/p&gt;

&lt;p&gt;An easy scenario like that is when there is &lt;code&gt;display: none&lt;/code&gt; on a element like below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#idOfElement {
    display: none;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will result in nothing being added to the &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/What_is_accessibility"&gt;accessibility tree&lt;/a&gt; and won't influence the positioning of elements. &lt;/p&gt;

&lt;p&gt;Next we need to look and see if we can actually scroll to the element if that is necessary. We are just going to test it as we don't want to actually scroll. This is important for elements that have been transformed to somewhere else on the page. This means that we can't always rely on looking at the DOM tree. I discussed this in a &lt;a href="https://dev.to%7B%7B&amp;lt;%20ref%20"&gt;}}"&amp;gt;previous post in 2013&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;From there we need to do a few checks on items like &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;option&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;optgroup&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;map&amp;gt;&lt;/code&gt;. &lt;code&gt;&amp;lt;option&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;optgroup&amp;gt;&lt;/code&gt;  items are "hidden" unless you click on them we assume they are visible... well mostly.&lt;/p&gt;

&lt;p&gt;Then we move on to checking the size of the element. For elements that have a 0 size we say they are not visible. We also check their opacity. If the opacity is 0 then we don't view the element as visible.&lt;/p&gt;

&lt;p&gt;Once we have done these tests we need then recursively walk the DOM and redo all the tests until we reach the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/documentElement"&gt;&lt;code&gt;documentElement&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why the recursion?
&lt;/h3&gt;

&lt;p&gt;Well unfortunately due to CSS we don't always know at what level of the DOM. We need to check each node along the way back. It does mean that &lt;code&gt;isDisplayed&lt;/code&gt; can be a little slow to run but it gives us a good approximation if the element would be visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can't we just ask the browser if an element is visible?
&lt;/h2&gt;

&lt;p&gt;Unfortunately no. Browsers when working out what to render they build up display lists and then send these over to the window manager for it to do all the heavy lifting. Browsers have in the past never worried too much about how efficiently the display list was generated. The window manager will try make the display list more efficient and then render. Great!&lt;/p&gt;

&lt;p&gt;Now, the thing with display lists is they only tell the window manager what to render for the viewport. The viewport is the area of the page that you can see when you are using the browser. We want &lt;code&gt;isDisplayed()&lt;/code&gt; to tell us if an element &lt;strong&gt;&lt;em&gt;will be&lt;/em&gt;&lt;/strong&gt; displayed. &lt;/p&gt;

&lt;p&gt;We also get into the realms of partially obscured elements. How do we know if an element is truly visible or just a small part is visible. Here we could use some web APIs like &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/elementFromPoint"&gt;&lt;code&gt;document.elementFromPoint(x, y);&lt;/code&gt;&lt;/a&gt;. Again, this would only tell us about elements that are in the viewport and then there are cases where it an element might be covering another but clicks go to the "hidden element".&lt;/p&gt;

&lt;p&gt;I go into this in a little more detail in my Selenium Conf London 2016 talk. You can watch the &lt;a href="https://www.youtube.com/watch?v=hTa1KI6fQpg"&gt;video&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Unfortunately, no one wants to specify how this would work in a browser so until then we need to have our own way of doing these calculations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;p&gt;Normally I would put a link to the WebDriver spec here for this command but you can read the &lt;a href="https://w3c.github.io/webdriver/#element-displayedness"&gt;appendix&lt;/a&gt; which tells drivers what end point to add.&lt;/p&gt;

&lt;p&gt;You can also go down the rabbit hole and look at the &lt;a href="https://github.com/SeleniumHQ/selenium/blob/master/javascript/atoms/dom.js#L573-L616"&gt;code&lt;/a&gt; that does all this work.&lt;/p&gt;

&lt;p&gt;Newer posts will also be appearing on my &lt;a href="https://www.theautomatedtester.co.uk/blog"&gt;blog&lt;/a&gt; first&lt;/p&gt;

</description>
      <category>testing</category>
      <category>automation</category>
      <category>browsers</category>
    </item>
    <item>
      <title>How Selenium Works: Episode 2 - Navigation</title>
      <dc:creator>David Burns</dc:creator>
      <pubDate>Mon, 02 Mar 2020 22:56:42 +0000</pubDate>
      <link>https://dev.to/automatedtester/how-selenium-works-episode-2-navigation-48ij</link>
      <guid>https://dev.to/automatedtester/how-selenium-works-episode-2-navigation-48ij</guid>
      <description>&lt;p&gt;After an interaction on the last weekend of January 2020, on a Selenium Issue where someone said “why can’t you just…” after I explained the issue I thought that I would start explaining commands in Selenium WebDriver and why we landed on the design that we have today.&lt;/p&gt;

&lt;p&gt;I will repeat this on every page of the series but a lot, an annoying amount sometimes, of thinking goes into how every little bit of Selenium works. &lt;/p&gt;

&lt;p&gt;In this episode we are going to look into the sheer amount of work that goes into navigation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;

&lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Firefox&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://www.theautomatedtester.co.uk"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can see above... it looks easy enough right... no!&lt;/p&gt;

&lt;p&gt;Actually, it leads me to a pet peeve in interviews. If someone ever asks you to ever describe what happens in a browser when you type a URL and press enter there is a high probability that they have no real idea what goes into navigation. Anyway... back to Selenium and how we navigate.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;code&gt;driver.get&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;Once we send the request over the &lt;a href="https://dev.to/automatedtester/how-selenium-works-episode-1-transportation-26de"&gt;transportation layer&lt;/a&gt; the real fun starts. We need to figure out where we want to go and tell the browser to start going there for us. Unfortunately this will lead to the first of the many problems for automators.&lt;/p&gt;

&lt;h2&gt;
  
  
  Certificates
&lt;/h2&gt;

&lt;p&gt;If you have ever worked in major corporate companies where technology is not the core then you will understand the pain that a development team might have to endure. Now double that pain and you're starting to get an idea of the pain that testers and automators have to deal with.&lt;/p&gt;

&lt;p&gt;One of these pains is certificates. Companies are cheap and will do self-signed certificates and other monstrosities. Especially in the early days of Selenium when there wasn't services like &lt;a href="https://letsencrypt.org/"&gt;Let's Encrypt&lt;/a&gt;. And even now, most Developers and QA teams rarely have access to change configurations on their test environments or on their CI servers. We needed to come up with a way to circumvent the certificates. (&lt;em&gt;This is one of the first reasons why Selenium is seen as a security risk&lt;/em&gt;)&lt;/p&gt;

&lt;p&gt;So each of the browsers will allow the poorly configured certificates through when we automate. It's because if we didn't a lot of testers/developers would never be able to test their sites. &lt;/p&gt;

&lt;p&gt;Now... that we go round the first problem we need to move on to getting the page to load.&lt;/p&gt;

&lt;h2&gt;
  
  
  Loading
&lt;/h2&gt;

&lt;p&gt;Once we have got round the certificates we get the page to load. Luckily we don't need to do anything more than the equivalent of&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;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://www.theautomatedtester.co.uk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="c1"&gt;// or&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://www.theautomatedtester.co.uk&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;h2&gt;
  
  
  Done...
&lt;/h2&gt;

&lt;p&gt;When Selenium has "finished" a command it will return. So, we just need to wait for the page to be finished loading. To be honest, what does &lt;em&gt;"finished loading"&lt;/em&gt; even mean.&lt;/p&gt;

&lt;p&gt;In the browser it will fire a number of different events. We will know when the page has been shown and then tell you what it's &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState"&gt;&lt;code&gt;readyState&lt;/code&gt;&lt;/a&gt;. Selenium will check all of that and it will also wait for the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/DOMContentLoaded_event"&gt;&lt;code&gt;DOMContentLoaded&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Then there is the problem if you're on the page and you try navigate to an anchor on the page. Let's look at the following example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;

&lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Firefox&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://www.theautomatedtester.co.uk"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://www.theautomatedtester.co.uk#someAnchor"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Oh look, none of the page loading events are going to be fired! Yay? Stupid browser is being efficient and will just scroll to the anchor. This means that we can't solely depend on events coming out of the page.&lt;/p&gt;

&lt;p&gt;No, so we need to have specialised code for this case and what "done" means in this case. If we get this wrong it's going to create a lot of unstable tests. Unstable tests make people grumpy and we don't want grumpy developers, there are enough of them in the world without unstable tests.&lt;/p&gt;

&lt;p&gt;Once we have done those checks, and you can manipulate how we look at those events, if you want it to load quicker, using the &lt;a href="https://w3c.github.io/webdriver/#dfn-page-loading-strategy"&gt;Page Load Strategies&lt;/a&gt;. This is more of a power user feature so I wouldn't worry about them now but they affect how quickly the navigation command &lt;/p&gt;

&lt;h2&gt;
  
  
  What about JavaScript Frameworks and navigation
&lt;/h2&gt;

&lt;p&gt;This is where there is "fun". A lot of frameworks will do a lot of loading after their initial load on to the page. If you have ever worked on a single page app, or have ever used a single page app, you will have seen a lot of items render as the data comes in. Unfortunately it does mean that you can't just rely on the navigation command returning. You will have to add a &lt;code&gt;WebDriverWait&lt;/code&gt; command to your code, as shown below, to make sure your test is in the right state before going off to do what it needs to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;selenium.webdriver.support.wait&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;WebDriverWait&lt;/span&gt;

&lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Firefox&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://www.theautomatedtester.co.uk"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebDriverWait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;until&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_element_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;someId&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;When loading a page, don't always rely on Selenium returning when the page has finished. If you need to look at an element on the page then do that. Just be aware of how the JavaScript on the page could mutate the page after the initial downloads are done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://w3c.github.io/webdriver/#navigate-to"&gt;Navigation Specification Prose&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://w3c.github.io/webdriver/#dfn-table-of-page-load-strategies"&gt;Page Load Strategies&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>testing</category>
      <category>automation</category>
    </item>
    <item>
      <title>How Selenium Works: Episode 1 - Transportation</title>
      <dc:creator>David Burns</dc:creator>
      <pubDate>Fri, 28 Feb 2020 09:06:23 +0000</pubDate>
      <link>https://dev.to/automatedtester/how-selenium-works-episode-1-transportation-26de</link>
      <guid>https://dev.to/automatedtester/how-selenium-works-episode-1-transportation-26de</guid>
      <description>&lt;p&gt;After an interaction on the last weekend of January 2020, on a Selenium Issue where someone said “why can’t you just…” after I explained the issue I thought that I would start explaining commands in Selenium WebDriver and why we landed on the design that we have today.&lt;/p&gt;

&lt;p&gt;I will repeat this on every page of the series but a lot, an annoying amount sometimes, of thinking goes into how every little bit of Selenium works. &lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Selenium, by chance and being good at what it does, is used by millions of people around the world as well. It's how companies from Microsoft and Google to the small startup make sure that their site works in every browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does Selenium talk to the browser?
&lt;/h2&gt;

&lt;p&gt;Selenium, over the years, decided that we were going to use HTTP to speak to the browser. We built a REST-ish API that every client binding could use and hopefully get the same results. &lt;/p&gt;

&lt;h3&gt;
  
  
  HTTP and REST-ish? Really?
&lt;/h3&gt;

&lt;p&gt;Yea... &lt;/p&gt;

&lt;p&gt;Let's start with the HTTP part. When we started we had to have a unique way to speak for each browser based on the best way to speak to them. So for Internet Explorer we wrote COM code. It was fine, it worked but gave us nightmares. For Firefox we wrote a monstrocity that read line by line and, thankfully, due to Mozilla's "make the browser yours" attitude we could do a lot. Opera allowed us to go in via the DevTools protocol.&lt;/p&gt;

&lt;p&gt;Now, it meant that, especially in the early days of WebDriver, we would need to maintain N: M bindings where N is the language bindings and  M is the browsers we support. This is not a road to a good product. We decided that we need something that every language would understand. We also needed something that would be pretty robust. HTTP was chosen and we set about building the &lt;code&gt;JSONWireProtocol&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;JSONWireProtocol&lt;/code&gt; is where we built a REST-ish interface that would speak JSON. I say REST-ish because it didn't follow all the principles of REST but enough to make it powerful for our needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does it relate to things now?
&lt;/h3&gt;

&lt;p&gt;The Web, the internet, and the world has moved on. Why hasn't Selenium? &lt;/p&gt;

&lt;p&gt;This is a good question and the thing is we are trying to move things on. Unfortunately the web has a state where it is broken unless it is working. HTTP is pretty robust as a protocol. It can also allow people to build up clusters for testing without having to worry too much about how the multiplexing would work. This is the reason why Selenium Grid was created and is still a pretty good choice when it comes to farming out your testing to multiple devices and multiple machines.&lt;/p&gt;

&lt;h3&gt;
  
  
  But  is more like the web, be like them.
&lt;/h3&gt;

&lt;p&gt;So... There are tools that use Chrome's Debug Protocol to drive the browser and some of the things they do better than Selenium are down to their choice of how they speak to the speak to the browser. Unfortunately it's a Chrome proprietary protocol and Google are not interested in working with other browsers on making it not.&lt;/p&gt;

&lt;p&gt;Also, ignoring the interesting design choices from the the Google team, there is the problem that we have to have a permenantly open connection. In this case it uses WebSockets but if you remember my comment earlier about the internet is down until it's up. WebSockets would be constantly re-establishing the connection. There is also the problem of how much traffic would be going up and down that pipe. &lt;/p&gt;

&lt;p&gt;This is fine for puppeteer where you are only speaking to something on your local machine but if you are combining a CI service, like Circle CI or TravisCI and something like AWS Device Farm, Sauce Labs, or BrowserStack you suddenly have a lot of internet inbetween you and your runner and that data needs to get somewhere.&lt;/p&gt;

&lt;p&gt;The W3C Browser Testing and Tools Working group, which is made up of browser vendors and Selenium folk, are trying to design what this will look like to make sure that we can make it cross browser from the start without having to do weird hacky patches to browsers and ship those browsers ourselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want to read more?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://w3c.github.io/webdriver/#processing-model"&gt;WebDriver Specification details about transport&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Also other episodes are appearing on my &lt;a href="https://www.theautomatedtester.co.uk/blog"&gt;blog&lt;/a&gt; before they on here&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
  </channel>
</rss>
