Transcripted Summary

WebDriver can handle any type of interaction with a web page. However, it is a complex API. Thankfully, it's similar between different programming languages.

If you ever get stuck, I recommend reading the Python docs online.

Here are a few of the WebDriver methods and properties I find myself calling frequently.



The left column shows calls directly from the WebDriver instance, which we named browser in our code.

  • current_url returns the URL of the page currently loaded in the browser

  • find_element returns an object representing the first element found by a locator. If no element is found, then this method throws an exception

  • find_elements, plural, returns a list of element objects found by a locator. In this case, if no elements are found, then this method returns an empty list

  • The Python WebDriver also includes a find_elemen_by_*method for each locator type. Typically, I don't use these methods because I prefer to use 2-part locator tuples, but many people prefer the shorter syntax

  • get loads a given URL in the browser

  • maximize_window maximizes the browser's window size

  • quit closes a browser and then terminates the process

  • refresh refreshes the current page in the browser

  • save_screenshot will capture the current browser window and save it to an image file

  • title returns the page's title


The right column shows calls for element objects returned by the find_element methods.

  • clear removes all text from a text input field

  • click clicks an element

  • find_element* methods on an element object will locate elements starting with the current element as the root

  • get_attribute returns the value of an HTML attribute; while get_property returns the value of an HTML property

  • is_displayedreturns true if the element visually appears on the page and isn't hidden

  • location returns the X and Y pixel coordinates of the elements

  • send_keys sends keystrokes to the elements like typing in a text input

  • size returns the pixel dimensions of the elements

  • text returns the text value of the elements

The best way to learn the Python WebDriver API is simply to do the code.

I have our project open here, and I've opened it to the search page.


# Example Code - pages/search.py

"""
This module contains DuckDuckGoSearchPage,
the page object for the DuckDuckGo search page.
"""

from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys

class DuckDuckGoSearchPage:

  # URL
  URL = 'https://www.duckduckgo.com'

  # Locators
  SEARCH_INPUT = (By.ID, 'search_form_input_homepage')

  # Initializer
  def __init__(self, browser):
    self.browser = browser

  # Interaction Methods
  def load(self):
    self.browser.get(self.URL)

  def search(self, phrase):
    search_input = self.browser.find_element(*self.SEARCH_INPUT)
    search_input.send_keys(phrase + Keys.RETURN)

You'll notice some differences.

First of all, I've added a new Selenium WebDriver import for this thing called Keys. We'll need that for one of the methods we implemented below.

Our class should look pretty familiar.

It still has our locator and it still has our initializer, but the interaction methods have now been implemented. Let's look at one at a time.


We know that the load method should load the page.

So, if you recall from our previous slide, we want to use the get method for our WebDriver. The get method takes in a β€œURL”, which I've put up here as a class variable.

That's all we need to do to load the webpage.

Next, let's look at the search method.


We know the search method should take in a textual phrase and enter that phrase onto the DuckDuckGo search page.

What we'll need to do is we'll need to locate the search_input element and then send the phrase to it.

To locate the search input elements, we'll need to say browser.find_element and we'll pass in our SEARCH_INPUT locator.

Now you may be wondering what this asterisk is for.

Well, the find_element method takes two arguments β€” the locator type and then the query β€” but SEARCH_INPUT is a tuple


This asterisk is a standard Python thing that will expand tuples into positional arguments that can be passed into methods.

By adding this here, I can essentially pass my tuple, my locator, into the find_element method. If it's successful, it will return an object representing the search_input element on the page.


Once I have that element, I can send_keys to it for my search phrase.

I'll also want to add on the Keys.RETURN. That comes from that import we saw before. The return key will essentially commit that search and then proceed to start loading the search results page.


Now you may be wondering what happens if this find_element call for my SEARCH_INPUT doesn't actually find the search input element.

Maybe the page isn't loaded yet or maybe the locator's bad, or maybe there's some other kind of problem. If this call fails to find the element, then it will raise an exception. We don't necessarily need to handle the exception here. We can just let it bubble up.

Ultimately, pytest will capture that exception at the test case execution level, and it will log a failure for the test. Then when we come and read the reports later, we could find it and try to figure out what went wrong.

Let's look at the result page next.


# Example Code - pages/result.py

"""
This module contains DuckDuckGoResultPage,
the page object for the DuckDuckGo search result page.
"""

from selenium.webdriver.common.by import By

class DuckDuckGoResultPage:

  # Locators
  RESULT_LINKS = (By.CSS_SELECTOR, 'a.result__a')
  SEARCH_INPUT = (By.ID, 'search_form_input')

  # Initializer
  def __init__(self, browser):
    self.browser = browser

  # Interaction Methods
  def result_link_titles(self):
    links = self.browser.find_elements(*self.RESULT_LINKS)
    titles = [link.text for link in links]
    return titles

  def search_input_value(self):
    search_input = self.browser.find_element(*self.SEARCH_INPUT)
    value = search_input.get_attribute('value')
    return value

  def title(self):
    return self.browser.title

Like the search page, the result page code should look familiar.

Again, we have the locators and the same initializer, but we've implemented the interaction methods.


The result_link_titles method should return a list of all link_titles for the results.

This call is going to look very similar to the search one in that we have to find some elements. However, this one uses the find_elements plural. We pass in the locator for my result links and I'll get those links back here in this variable, which will be a list.

Now I don't want to return the elements themselves. What I want to return is the text of each element that was found.

I can use a simple list comprehension here to get the titles β€” titles = [link.text for link in links] β€” and that is the value I want to return. It should be a list of strings, not a list of elements.


Next, let's look at the search_input_value method.

This method should get the text value of my search input field from the result page. Again, I'll use the singular find_element method and pass in my search input locator.

Now instead of sending keys to this, I want to get the value from it. To do that, I'll need to use the get_attribute method and look for the attribute named β€œvalue” and ultimately, that's the text value that I'll want to return.


Now you may be wondering, why did we use get_attribute instead of just the text property for the search_input element?

Whenever you're dealing with text input elements where you can type something in, interestingly, the text property of that is going to be the empty string.

You'll need to use the get_attribute of the value to get the value that the user typed in. Be careful, that usually trips up a lot of people.


Finally, let's look at the title method here.

This one, we don't need to use a find_element method because like we said previously, the title is an attribute of the page and not an element of the page.

We simply call self.browser (our WebDriver instance) .title.

As we said before, the WebDriver API is long and complex. I can only cover a few methods in this course here, so I encourage you to give some of these other methods and properties a try and to read up on the docs so that you know how to do any interaction.



Resources



Β© 2021 Applitools. All rights reserved. Terms and Conditions Privacy Policy GDPR