Test Automation with Selenium (Python Track)

From Training Material
Revision as of 08:58, 2 October 2017 by Ksolis (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Nobleprog.svg


Test Automation with Selenium (Python Track)


Introdution to Selenium

Selenium consists of a set of tools

  • Selenium IDE
  • Firefox add-on
  • Simple record and play back of browser interactions
  • Selenium WebDriver
  • Create programs to automate web browser's
  • There are programmatic drivers for most of the common Browsers
  • i.e. Firefox, Internet Explorer, Safari, Chrome, etc.
  • Given the various web browser drivers - thus the name WebDriver

Selenium IDE Introduction

  • Selenium IDE is useful for building starting test cases or test suites
It allows recording of user interactions with the browser (Firefox)
It allows building of test cases by adding commands and HTML elements they will act upon
It allows the test cases to be run (to make sure they work)
It allows the test cases to be saved in various languages such as Python

Selenium WebDriver Introduction

  • Selenium WebDriver is a tool that automates browsers
  • Automation refers to giving commands to a browser
  • For example: browser open, browser go to web site page, browser give me the tags of this type, browser close.
  • When given the commands the browser can be watched as it opens, goes to pages, closes, etc.

  • Selenium WebDriver is a tool that can make assertions about web page data and tags
  • Assertions when using Python are from the Python UnitTest modules
  • Assertions are questions that that can be answered as true or false
  • Does this web page have the following data?
  • Does this web page have the following HTML tag?
  • Does this web page exist?
  • Assertions can be failed

  • Selenium WebDriver is a tool that can put data into form inputs on a web page
  • Put in a username and password
  • Put in a search term
  • Fill out a profile for a user

  • This makes Selenium WebDriver a very powerful tool for the testing of web pages and content

Selenium WebDriver

  • A browser WebDriver has a set of Programming Bindings
  • These bindings allow a program to automate the Browser
  • For example the following Python code opens a Firefox browser, gets Yahoo's main page, and finds an element in that page
browser = webdriver.Firefox() # Get local session of firefox
browser.get("http://www.yahoo.com") # Load page
assert "Yahoo!" in browser.title
elem = browser.find_element_by_name("p") # Find the query box
driver.quit() # Close the browser window 
  • There are Selenium bindings in several programming languages
  • Python is one language for which bindings exist
  • These allow a Python program to control a browser
  • The browser can be instructed to;
  • Open
  • Request web pages from sites
  • Close
  • Once a page is retrieved it can have:
  • Its elements analyzed
  • Its inputs filled with data (i.e. HTML form inputs)
  • For example a search box or a username and password filled in
  • The form can be submitted
References
Useful Selenium with Python Docs
Official Selenium with Python Docs

WebDriver Installation and Configuration

The following sections describe the steps to be WebDriver installed they include:

  • Install Python
  • Install Selenium Python Bindings Package for WebDriver
  • Install a Python IDE

Install Python

  • Go to the python.org homepage referenced below and download the latest version of Python
Presently this is version 3.4
For Windows get the 64 (x86-64) or 32(x86) bit version depending upon your type of system
Is your computer a 64 bit or 32 bit computer
Windows see Windows running 64 or 32 bit?
Mac see Mac OS X running 64 or 32 bit?
  • Install Python using the installer for your operating system type (Windows, Mac OS X)
  • Put the python folder into your environment's path variable
Make sure you do not delete your path by mistake, it is hard to get it back
Reference

Python.Org

Install Selenium Python Bindings Package for WebDriver

  • Go to the Selenium Package for Python website and download the tar.gz file
  • Extract the tar.gz file using a zip file extractor
  • Open a command prompt and move to the unzipped folder using cd and dir or similar commands on the Mac
It is the selenium-2.45.0 folder in the downloads folder on this computer
  • In the command prompt run the command -- python setup.py install
You should see a setup.py program in the unzipped selenium-2.45.0 folder
If the system cannot find the python application it means that the path is not setup correctly (most likely)
Note - installing the package causes it to be put into the python library so it can be used in Python programs and with PyCharm below
References

Selenium Python Bindings Package

Install a Python IDE

  • To use the Selenium WebDriver(s) you will be programming in Python
  • It is easier to use an IDE when programming
  • There are two possibilities for an IDE that seem reasonable PyCharm and Eclipse with a Python plug-in

PyCharm

This is very easy to use and not quite as complex as Eclipse
For this class this IDE will be used
Installing PyCharm
  • Go to the PyCharm website PyCharm website
  • Download PyCharm Community Edition
  • Install PyCharm using the downloaded install program
Choose to associate it with .py files during installation

Eclipse for Python

  • Download Eclipse Eclipse website
  • Download and install a Python plug-in or download liClipse for Python
PyDev plug-in for Eclipse Python Development
LiClipse Eclipse for Python Development

Selenium Python Primer

  • Selenium WebDriver uses a set of programmatic bindings
  • These allow automation of various web browsers
Such as Firefox, Internet Explorer, Safari, Chrome, etc.
  • The bindings are written for several programming languages
Such as Phython, Java, Ruby, JavaScript, PHP, C#, etc.
  • To use Phython the language must be understood
  • Which is the purpose of the following primer

Python Primer

XPath Navigation Primer

  • XPath is used to navigate through elements in a XML document
  • HTML is a subset of XML when properly formated
  • XPath can be used to navigate through elements in an HTML document
  • XPath is used in Selenium as element locators

XPath Primer

Cascading Style Sheets

  • Cascading Style Sheet selectors can be to locate elements
This is similar to using XPath locators
  • In CSS the following symbols are used:
. - this refers to a tag's class attribute
# - this refers to an tag's id attribute
  • Note that CSS may not work at times because the attributes will not give a unique element
For example classes may be used multiple times in a page on various tags
  • Note that in using CSS only the selectors are being used
  • General form of the selector:
css=<HTML tag><.or #.<value of class or id attribute>

Example
css=input#Password[type='password'][name='Passwd']
css=#reauthEmail


References
Using CSS selectors as element locators
CSS and XPath Cheat Sheet

HTML Tags

  • The easiest way to learn/use HTML is to use online references
Here are a couple of the best ones
Look up others using a search engine i.e. Google etc.
References
W3Schools on HTML Tags
TutorialsPoint Tutorial on HTML

Set Up a Tomcat server for Testing

Understanding the development process

  • It may be a good idea to have a web server
It helps to have HTML elements isolated so you can determine how to set up Selenium commands
It helps in working with AJAX elements to have them isolated
It helps in training to have a server with examples that WebDriver Or Selenium IDE can run against
  • Tomcat is open source and fairly easy to set up

Set up a Tomcat development web server

  • The web server builds and serves web pages to browsers
    • Browsers - Firefox, Chrome, Internet Explorer, Safari, etc.
  • A Development web server generally is on a developer's computer
    • The code base is put onto the server such that the developer can step through web pages that are built by the server.
    • These days this is usually done in an Integrated Development Environment (IDE)
      • Eclipse
      • Netbeans
      • Visual Studio
      • Intellij

Install the Java SE JDK

Hands on Exercise - Install the Java JDK:
Using the following document install the Java JDK that corresponds to the type of Operating system that exists on your computer (Windows, Mac OS, Linux x64, etc.). The installation steps will be approximately the same for each operating system.
Installing the JDK

Install Eclipse IDE

Hands on Exercise - Install an Integrated Development Environment (IDE):
Using the following instructions install Eclipse on your computer. Eclipse is an Integrated Development Environment commonly used by developers. Installation steps will be approximately the same for all operating systems. There is only one installation zip file for all operating systems.
Installing Eclipse

Install Apache Tomcat

Hands on Exercise - Install a Web Server
Install Tomcat on Windows
Install a WAR file into Tomcat Selenium Testing WAR
The WAR file goes into the Tomcat webapps directory

WebDriver - Using Python UnitTest

  • UnitTest specifies a series of test cases that are to be run against a web site
  • It allows a setUp method and a tearDown method
These two are run before and after each test case in the Unit Test
Each test must be a method that starts with "test"
  • Assert methods are provided by the Testcase base class
  • Tests can be skipped by using appropriate decoration
i.e. @unittest.skip("demonstrating skipping")


Example of UnitTest

from selenium import webdriver
import unittest

class UnitTestExample(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Firefox() # note that this creates a class instance variable
        self.driver.implicitly_wait(30) # when testing AJAX this would not be used
        self.base_url = "http://somewebsite.com" # sets up another class instance variable
        self.verificationErrors = []

    def testWebSite1(self): # a first test case there can be others
        driver = self.driver  # class instance variable used here
        driver.get("http://somewebsite.com")

        # put your test code here


    def tearDown(self):
        self.driver.quit()
        self.assertEqual([], self.verificationErrors)

if __name__ == "__main__": # allows unittest to start by running this class file
    unittest.main()  # start the main method of unittest
  • Unittest has a testSuite class which can aggregate tests.
There are other ways of aggregating such as NOSE
References
Python unittest Reference Page
Python Testing on unittest
Dr Dobbs on Python unittest
NOSE - is nicer testing for python
Testing with NOSE Documentation

WebDriver - Using The Python Bindings

  • The Python Bindings are a set of classes and functions that enable WebDriver in a Python program
  • To use them generally it is best to program in an IDE such as PyCharm or Eclipse with a Python plugin
  • When stuck with WebDriver, solutions can be found:
By recording a session with Selenium IDE and then export to Python
By building a session in Selenium IDE manually while testing each step
Does each step work?
Try different locators when the commands with locators are failing
Put in echo statements to debug
Put in pauses to see what is happening
Reduce the complexity of the HTML so it is easier to work with a page
You May need a web server of your own to test the commands
By web searches for solutions to the problem
  • The general steps in using the bindings are listed in an approximate order below


Choose which WebDriver browser to use

  • There are drivers for most common browsers
  • The driver can be set up in the code of a Python application
  • The driver can be set up in the setup method of a unittest (see section below)
In the image below the various Browser classes are listed as part of the webdriver module

WebDriver Methods

Load a Page

  • To load a page the webdriver Browser classes have get methods

For example in the Firefox driver the code is:

driver.get("http://localhost:8080/Web_Project_1/seleniumTest.jsp")
  • Generally it is a good practice to wait until the web page has loaded before using it
    • This can be done using either an implicit or explicit wait

Explicit or Implicit Wait

  • Mixing explicit and implicit waits can cause unpredictable waits

Explicit Waits

  • Explicit waits makes the web driver wait for a certain condition to occur
  • This can be done using WebDriverWait along with an ExpectedCondition
It should be noted that the locator is very important.
XPath seems to be a good way of specifying the locator
Note that this example is one where a page is loaded
It is not using AJAX

Example in Python

from selenium import webdriver # The driver for the Browser such as Firefox, etc.
from selenium.webdriver.common.by import By # Specifies the method of finding an element - by id, by name, etc.
from selenium.webdriver.support.ui import WebDriverWait # The function that implements the wait concept for a driver
from selenium.webdriver.support import expected_conditions as EC # specifies the type of wait condition

driverFirefox = webdriver.Firefox() # get a particular driver such as Firefox
driverFirefox.get("http://somedomain/url_that_delays_loading") # load a web page 
try:
    # wait for an element myDynamicElement to be loaded or until 10 seconds have past
    element = WebDriverWait(driverFirefox, 10).until(EC.presence_of_element_located((By.XPATH, "//div[@id='div1']/div")))
finally:
    driverFirefox.quit()
  • Common Expected Conditions
Most of these work with a page being loaded
Only some of them work with AJAX
For example the title of the page will not change with AJAX
However, some elements, their attributes, or their child text contents will change with AJAX
   ::title_is
   ::title_contains
   ::presence_of_element_located
   ::visibility_of_element_located
   ::visibility_of
   ::presence_of_all_elements_located
   ::text_to_be_present_in_element
   ::text_to_be_present_in_element_value
   ::frame_to_be_available_and_switch_to_it
   ::invisibility_of_element_located
   ::element_to_be_clickable - it is Displayed and Enabled.
   ::staleness_of
   ::element_to_be_selected
   ::element_located_to_be_selected
   ::element_selection_state_to_be
   ::element_located_selection_state_to_be
   ::alert_is_present

See the topic further below on AJAX

References

WebDriver Advanced Usage
Selenium Python Bindings - Waits
Python Expected Conditions
How To WebDriverWait
Using waitForCondition

Implicit Waits

  • Implicit waits make the web driver wait for a certain amount of time
  • Once set in the WebDriver it stays until the WebDriver quits

Example of Implicit Wait

driver = webdriver.Firefox()
driver.implicitly_wait(30)
References
Selenium Implicit Waits
Selenium on Waits

Locating UI Elements

  • For HTML pages the elements are the HTML tags i.e. div, a, span, input, iframe, etc.
  • A tag usually needs to be located so that it can be clicked, have text entered, be selected, etc.
  • There are several ways to locate an element on the page
  • The most useful of these are listed below

By id

  • Find an element by using its id attribute
  • For example the html and its locator would be
The HTML:
<div id="idOfElement">some text or other HTML</div>

The locator examples:
element = driver.findElement(By.id("idOfElement"))
driver.find_element_by_id("div1").click()

Note: pages often have the same ids for numerous elements so the use of this locator may be limited

By Name

  • Find an element using the name attribute
The HTML:
<input type="text" name="FirstName" value="First Name">

The locator example:
driver.find_element_by_name("FirstName").clear()

ByXPath

  • XPath is a very useful locator since it can distinguish most elements
  • For AJAX modified or created elements it works very well
The HTML:
<input type="checkbox" name="vehicle" value="Bike"> I have a bike<br>

The locator example:
driver.find_element_by_xpath("//input[@value='Bike']").click()

By Link Text

  • Locate a link ("a" tag> element by the link text
The HTML:
<a href="formsDemo.jsp">Forms Demo</a>

The locator:
driver.find_element_by_link_text("Forms Demo").click()

By Partial Link Text

  • Find a link ("a" tag) by partial link text
The HTML
<a href="formsDemo.jsp">Forms Demo</a>

The locator:
driver.find_element_by_partial_link_text("Forms")


References
WebDriver Commands and Operations
Firefox WebDriver Element Locator Add-on
Writing Reliable Locators
Regular expression tester

User Input in Forms

  • HTML Forms take input from users
  • In general they have:
Textboxes
Checkboxes
Radio Buttons
Select dropdowns with options
  • Testing these requires
locating the correct element
Entering text
Clicking on elements and options
Clicking on submit
Checking the data on the action page
The action page is the page that submit invokes
  • One of the most useful ways of locating an element is by XPath
# Example of entering text
driver.find_element_by_name("FirstName").clear()
driver.find_element_by_name("FirstName").send_keys("Hermione")

# Example of clicking checkboxes
if not driver.find_element_by_xpath("//input[@value='Bike']").is_selected():
            driver.find_element_by_xpath("//input[@value='Bike']").click()

# Example of click radio buttons
driver.find_element_by_xpath("(//input[@name='gender'])[2]").click()

# Example of choosing an entry in a drop down select list
Select(driver.find_element_by_xpath("//select[@name='selectBox1']")).select_by_visible_text("Audi")

# Example of click the submit button
driver.find_element_by_xpath("//input[@value='Submit']").click()
Hands on Exercise
  • Go to the page on the Tomcat server
http://ServerAddress:8080/Web_Project_1/userForm.jsp
  • Write a WebDriver program that will:
fill the username and password
Click on the submit button
Assert whether the login has succeeded
Prove that the login effects the page "anotherPage.jsp"

Handle Alerts

  • Alerts are handled with the Alert class
Accept and dismiss alerts
Enter Text into prompt alerts
  • The alert can be switched_to using the webdriver object

Example of code that popups up an Alert

<p>Click the button to display a confirm box.</p>

<button onclick="myFunction1()">Try it</button>

<p id="demo"></p>

<script>
<!--
function myFunction1() {
    var x;
    if (confirm("Press a button!") == true) {
        x = "You pressed OK!";
    } else {
        x = "You pressed Cancel!";
    }
    document.getElementById("demo").innerHTML = x;
}
//-->
</script>


Examples of Python Selenium Alert Testing code

class PopupWindows(unittest.TestCase):
    def test_popup_windows(self):
        driver = self.driver
        driver.get("http://localhost:8080/Web_Project_1/seleniumTest.jsp")
        driver.find_element_by_link_text("Popup Window Demos").click()
        driver.find_element_by_css_selector("button").click()
        self.assertEqual("I am an alert box!", self.close_alert_and_get_its_text())
        driver.find_element_by_xpath("//button[@onclick='myFunction1()']").click()
        self.assertEqual("Press a button!", self.close_alert_and_get_its_text())
        driver.find_element_by_xpath("//button[@onclick='myFunction2()']").click()
        alert = driver.switch_to.alert
        alert.send_keys("Mickey")
        self.assertEqual("Please enter your name", self.close_alert_and_get_its_text())
        pageSource = self.driver.page_source
        self.assertTrue("Mickey" in pageSource)
    def close_alert_and_get_its_text(self):
        try:
            alert = self.driver.switch_to.alert
            alert_text = alert.text
            if self.accept_next_alert:
                alert.accept()
            else:
                alert.dismiss()
            return alert_text
        finally: self.accept_next_alert = True
  • Note that when using Selenese the Alerts do not actually popup
Although they test correctly
  • Note that when using the Python bindings the Alerts do popup

Hands on Exercise

If possible work in groups to do this hands on exercise
  • Using the example code for putting up an Alert on a web page
  • Using the example Selenium code for testing an alert
  • Do the following
Write a simple set of HTML code that will put up an Alert
Put it onto the test Tomcat server
Prove that it works by accessing it
Write a Selenium program in Python that will test the Alert
Run the Selenium test against the web page


References

Selenium Alert

Interact with Popup Windows

  • Popup Windows can be invoked by:
JavaScript (see the example below)
Targets on a link ("a" tag)
  • To test these windows it is necessary to switch to them and then test

Example HTML code that will be in a popup window

<html>
<head>
<meta charset="ISO-8859-1">
<title>New Popup Window</title>
</head>
<body>
<h1>This is a popup</h1>

<h2>Please fill in the form</h2>
<br/>
<form action="seleniumTestAction.jsp">
First name: <input type="text" name="FirstName" value="First Name"><br>
<br/><br/>
<input type="submit" value="Submit">
</form>

</body>
</html>

Code that pops up the window

<a href="smallPopup.html" onClick="return popup(this, 'notes')">Display a popup</a>

<SCRIPT TYPE="text/javascript">
<!--
function popup(mylink, windowname)
{
if (! window.focus)return true;
var href;
if (typeof(mylink) == 'string')
   href=mylink;
else
   href=mylink.href;
window.open(href, windowname, 'width=400,height=200,scrollbars=yes');
return false;
}

Selenium test code for popup window

class PopupWindows(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Firefox()
        self.driver.implicitly_wait(30)
        self.base_url = "http://localhost:8080/"
        self.verificationErrors = []
        self.accept_next_alert = True
    
    def test_popup_windows(self):
        driver.find_element_by_xpath("//a[contains(@href, 'smallPopup.html')]").click()
        driver.switch_to.window("notes")
        driver.find_element_by_name("FirstName").clear()
        element = driver.find_element_by_name("FirstName")
        element.send_keys("Hermione")
        self.assertTrue("Hermione", element.text)
  • Node that when using Selenese the window does not actually popup
Although they test correctly
  • In Python WebDriver it does popup correctly

Hands on Exercise

  • Build a test program using the Selenium Test Code above
  • Test the popup window that can be seen at:
Go to http://servername:8080/Web_Project_1/seleniumTest.jsp
Go To link Popup Window Demos
Go to link Display a Test Popup

Navigation in History and Location

  • Moving backwards and forwards in history is accomplished with commands
  • driver.forward()
  • driver.back()

Cookies

  • With Selenium Cookies can be added, deleted, and retrieved
For example, making sure that a cookie was correctly added can be tested

The following example of cookie use is from the Selenium website

Reference See Selenium Site on WebDriver
# Go to the correct domain
driver.get("http://www.example.com")

# Now set the cookie. Here's one for the entire domain
# the cookie name here is 'key' and its value is 'value'
driver.add_cookie({'name':'key', 'value':'value', 'path':'/'})
# additional keys that can be passed in are:
# 'domain' -> String,
# 'secure' -> Boolean,
# 'expiry' -> Milliseconds since the Epoch it should expire.

# And now output all the available cookies for the current URL
for cookie in driver.get_cookies():
    print "%s -> %s" % (cookie['name'], cookie['value'])

# You can delete cookies in 2 ways
# By name
driver.delete_cookie("CookieName")
# Or all of them
driver.delete_all_cookies()

Compare Python to Java Bindings

  • Here is the code for testing the same page in Python and Java
The first uses the Python Selenium Bindings
The second uses the Java Selenium Bindings
Both sets of code came from using the Selenium IDE to prototype and then export to the two languages
The code was corrected after export to eliminate small errors made by Selenium in translating from Selenese
  • Note that both sets of code have several methods that are courtesy methods that can be used by the programmer
For example to work with JavaScript Alerts
The methods that are not test, setup, or teardown

Python Bindings code

class BuildFormsTestCase(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Firefox()
        self.driver.implicitly_wait(30)
        self.base_url = "http://localhost:8080/Web_Project_1/seleniumTest.jsp"
        self.verificationErrors = []
        self.accept_next_alert = True
    
    def test_build_forms_test_case(self):
        driver = self.driver
        driver.get("http://localhost:8080/Web_Project_1/seleniumTest.jsp")
        driver.find_element_by_link_text("Forms Demo").click()
        print("going to write in text boxes")
        driver.find_element_by_name("FirstName").clear()
        driver.find_element_by_name("FirstName").send_keys("Hermione")
        driver.find_element_by_name("LastName").clear()
        driver.find_element_by_name("LastName").send_keys("")
        driver.find_element_by_name("LastName").send_keys("Gran")
        driver.find_element_by_name("LastName").send_keys("ger")
        print("going to check boxes")
        if not driver.find_element_by_xpath("//input[@value='Bike']").is_selected():
            driver.find_element_by_xpath("//input[@value='Bike']").click()
        if driver.find_element_by_xpath("//input[@value='Bike']").is_selected():
            driver.find_element_by_xpath("//input[@value='Bike']").click()
        print("Going to click on I have a bike again")
        if driver.find_element_by_xpath("//input[@value='Car']").is_selected():
            driver.find_element_by_xpath("//input[@value='Car']").click()
        if not driver.find_element_by_xpath("//input[@value='Car']").is_selected():
            driver.find_element_by_xpath("//input[@value='Car']").click()
        if driver.find_element_by_xpath("//input[@value='Car']").is_selected():
            driver.find_element_by_xpath("//input[@value='Car']").click()
        if not driver.find_element_by_xpath("//input[@value='Car']").is_selected():
            driver.find_element_by_xpath("//input[@value='Car']").click()
        if driver.find_element_by_xpath("//input[@value='Car']").is_selected():
            driver.find_element_by_xpath("//input[@value='Car']").click()
        if not driver.find_element_by_xpath("//input[@value='Car']").is_selected():
            driver.find_element_by_xpath("//input[@value='Car']").click()
        print("going to select dropdown")
        Select(driver.find_element_by_xpath("//select[@name='selectBox1']")).select_by_visible_text("Audi")
        print("going to radio buttons")
        driver.find_element_by_xpath("(//input[@name='gender'])[2]").click()
        driver.find_element_by_xpath("//input[@name='gender'][1]").click()
        driver.find_element_by_xpath("(//input[@name='gender'])[2]").click()
        driver.find_element_by_xpath("//input[@value='Submit']").click()
    
    def is_element_present(self, how, what):
        try: self.driver.find_element(by=how, value=what)
        except NoSuchElementException as e:
            return False
        return True
    
    def is_alert_present(self):
        try: self.driver.switch_to.alert()
        except NoAlertPresentException as e:
            return False
        return True
    
    def close_alert_and_get_its_text(self):
        try:
            alert = self.driver.switch_to.alert()
            alert_text = alert.text
            if self.accept_next_alert:
                alert.accept()
            else:
                alert.dismiss()
            return alert_text
        finally: self.accept_next_alert = True
    
    def tearDown(self):
        self.driver.quit()
        self.assertEqual([], self.verificationErrors)

if __name__ == "__main__":
    unittest.main()


Java Bindings code

package com.example.tests;

import java.util.regex.Pattern;
import java.util.concurrent.TimeUnit;
import org.junit.*;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Select;

public class BuildFormsTestCase {
  private WebDriver driver;
  private String baseUrl;
  private boolean acceptNextAlert = true;
  private StringBuffer verificationErrors = new StringBuffer();

  @Before
  public void setUp() throws Exception {
    driver = new FirefoxDriver();
    baseUrl = "http://localhost:8080/Web_Project_1/";
    driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
  }

  @Test
  public void testBuildFormsTestCase() throws Exception {
    driver.get("http://localhost:8080/Web_Project_1/seleniumTest.jsp");
    driver.findElement(By.linkText("Forms Demo")).click();
    System.out.println("going to write in text boxes");
    driver.findElement(By.name("FirstName")).clear();
    driver.findElement(By.name("FirstName")).sendKeys("Hermione");
    driver.findElement(By.name("LastName")).clear();
    driver.findElement(By.name("LastName")).sendKeys("");
    driver.findElement(By.name("LastName")).sendKeys("Gran");
    driver.findElement(By.name("LastName")).sendKeys("ger");
    System.out.println("going to check boxes");
    if (!driver.findElement(By.xpath("//input[@value='Bike']")).isSelected()) {
      driver.findElement(By.xpath("//input[@value='Bike']")).click();
    };
    if (driver.findElement(By.xpath("//input[@value='Bike']")).isSelected()) {
      driver.findElement(By.xpath("//input[@value='Bike']")).click();
    };
    System.out.println("Going to click on I have a bike again");
    if (driver.findElement(By.xpath("//input[@value='Car']")).isSelected()) {
      driver.findElement(By.xpath("//input[@value='Car']")).click();
    };
    if (!driver.findElement(By.xpath("//input[@value='Car']")).isSelected()) {
      driver.findElement(By.xpath("//input[@value='Car']")).click();
    };
    if (driver.findElement(By.xpath("//input[@value='Car']")).isSelected()) {
      driver.findElement(By.xpath("//input[@value='Car']")).click();
    };
    if (!driver.findElement(By.xpath("//input[@value='Car']")).isSelected()) {
      driver.findElement(By.xpath("//input[@value='Car']")).click();
    };
    if (driver.findElement(By.xpath("//input[@value='Car']")).isSelected()) {
      driver.findElement(By.xpath("//input[@value='Car']")).click();
    };
    if (!driver.findElement(By.xpath("//input[@value='Car']")).isSelected()) {
      driver.findElement(By.xpath("//input[@value='Car']")).click();
    };
    System.out.println("going to select dropdown");
    new Select(driver.findElement(By.xpath("//select[@name='selectBox1']"))).selectByVisibleText("Audi");
    System.out.println("going to radio buttons");
    driver.findElement(By.xpath("(//input[@name='sex'])[2]")).click();
    driver.findElement(By.xpath("//input[@name='sex'][1]")).click();
    driver.findElement(By.xpath("(//input[@name='sex'])[2]")).click();
    driver.findElement(By.xpath("//input[@value='Submit']")).click();
  }

  @After
  public void tearDown() throws Exception {
    driver.quit();
    String verificationErrorString = verificationErrors.toString();
    if (!"".equals(verificationErrorString)) {
      fail(verificationErrorString);
    }
  }

  private boolean isElementPresent(By by) {
    try {
      driver.findElement(by);
      return true;
    } catch (NoSuchElementException e) {
      return false;
    }
  }

  private boolean isAlertPresent() {
    try {
      driver.switchTo().alert();
      return true;
    } catch (NoAlertPresentException e) {
      return false;
    }
  }

  private String closeAlertAndGetItsText() {
    try {
      Alert alert = driver.switchTo().alert();
      String alertText = alert.getText();
      if (acceptNextAlert) {
        alert.accept();
      } else {
        alert.dismiss();
      }
      return alertText;
    } finally {
      acceptNextAlert = true;
    }
  }
}

WebDriver - Read and Write Files

  • File can be written and read from within the Python Test code
  • The standard Python techniques of opening, reading, and writing files are used

Example of writing a file

f = open('workfile', 'w')

f.write("this is the file output")
f.close()

Hands on Exercise Write a test that does the following

  • read a username and password from a file
  • Use those to test the user login on the web page:
http://nameOfServer:8080/Web_Project_1/userForm.jsp
This is a page in the Web Project 1 WAR file
See the Section on Selenium Sample Zip Files

WebDriver - Parse a Web Page

  • Parsing a web page is done using Python code within your test

An Example of Parsing a web page

driver = webdriver.Firefox()
driver.get("http://www.google.com")
try:
    done = False
    inputTagList = []
    endIndex = 0
    count = 0
    while (not done):
        element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "tsf")))
        pageSource = driver.page_source
        print("The type is " + type(pageSource).__name__)
        # print(pageSource)
        stringLength = len(pageSource)
        print("stringLength = " + str(stringLength))
        startIndex = pageSource.find("<input", endIndex, stringLength)
        endOfString = stringLength - startIndex - 1
        print("endOfString is " + str(endOfString))
        #print(pageSource[startIndex:stringLength - 1])
        endIndex = pageSource.find(">",startIndex, stringLength - 1)
        print("startIndex = " + str(startIndex))
        print("endIndex = " + str(endIndex))
        theInputTag = pageSource[startIndex:endIndex + 1]
        print(theInputTag)
        if (startIndex == -1):
            done = True
        else:
            print("count is " + str(count))
            inputTagList.append(theInputTag)
    for inputTag in inputTagList:
        print(inputTag)

finally:
    driver.quit()

WebDriver with AJAX Modified Pages

  • What is AJAX
AJAX stands for Asynchronous JavaScript and XML
In JavaScript communication occurs with a server
The server data is then used to modify a portion of a page
A page reload does not occur
Thus portions of a page can be modified with data from a server
  • Testing AJAX
Page loading does not occur
The tester must determine what constitutes a change on the page
What are the characteristics of the change
Text change?
Elements are added?
Element contents change?
Once the change characteristics are determined
A test must be devised that can recognize the changes
The test must wait for the changes to occur
Network and server delay time is possible

An Example of AJAX from a JavaServer Page (JSP)

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Test AJAX functionality</title>
<script>
function loadDoc()
{
	// set up to make an ajax request to a server
	var httpRequest;
	if (window.XMLHttpRequest) { // Mozilla, Safari, IE7+ ...
	    httpRequest = new XMLHttpRequest();
	} else if (window.ActiveXObject) { // IE 6 and older
	    httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
	}
	//define the function that will handle the response from the server
	// note that this is a javascript shorthand method of defining an anonymous function
	httpRequest.onreadystatechange = function() {
		if (httpRequest.readyState==4 && httpRequest.status==200) {
			
	        document.getElementById('div1').innerHTML=httpRequest.responseText;

	    }
	}
        // Make the request to the server once the response occurs it will jump to the handler function
	httpRequest.open('GET', 'http://localhost:8080/Web_Project_1/ajaxResponseServlet', true);
	httpRequest.send(null);
}
</script>

</head>
<body>
<div id="div1" style="cursor: pointer" onclick="loadDoc()">Click Here for AJAX response</div>
</body>
</html>

Changes caused by the AJAX call are

The div tag with id="div1" has its innerHTML (i.e. Click Here for AJAX response) replaced with:

<div>Ajax response from Servlet</div>
<div>Hello Glad to hear from you</div>
<div>It is a nice day</div>

This gives a different a structure to the html of the page along with different content


  • How to test AJAX changes to a page
Load the page
Perform an action that invokes the AJAX code to change the page
Wait for the change to occur
Check that the changes is correct with an Selenium WebDriver assertion
Or a Selenium IDE assert or verify command (when prototyping your code)

Example of WebDriver Code to test an AJAX change

from selenium import webdriver # The driver for the Browser such as Firefox, etc.
from selenium.webdriver.common.by import By # Specifies the method of finding an element - by id, by name, etc.
from selenium.webdriver.support.ui import WebDriverWait # The function that implements the wait concept for a driver
from selenium.webdriver.support import expected_conditions as EC # specifies the type of wait condition

driver = webdriver.Firefox()
driver.get("http://localhost:8080/Web_Project_1/ajaxTest.jsp")

driver.find_element_by_id("div1").click()

element = WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.XPATH, "//div[@id='div1']/div")))

ajaxDivText = driver.find_element_by_xpath("//div[@id='div1']/div").text # test to see if the new div tag is there
print("ajaxDivText is " + ajaxDivText) # in a real test an assertion would be used here

driver.quit()

Hands on Exercise
Start the Tomcat server that has Web_Project_1 on it as an application
Determine how to write a test that will check for the contents of the second div tag that is a child of the //div[@id='div1'] tag
Use an XPath to do the above
Use UnitTest to specify your test case
Write an assertion instead of a print statement
Make the unit test both succeed and fail by changing your Python code
Most likely changing the assertion make the most sense
See what happens if you introduce an error in the XPath

References

Getting Started with AJAX
AJAX Testing using WaitForContition in Selenium IDE
Selenium WaitFor Commands in Selenium IDE

Building a test suite

  • Python unittest contains a testsuite class
Helps to build a test suite
  • The most useful parts of Test Suite are:

TestLoader - loads test cases from a file into the application TestSuite - the constructor can build a suite from loaded test cases TestRunner - runs a combined set of test cases

Example of building and running a test suite

import unittest
from buildFormsTestCase import BuildFormsTestCase
from popupWindows import PopupWindows

tests1 = unittest.TestLoader().loadTestsFromTestCase(BuildFormsTestCase)
tests2 = unittest.TestLoader().loadTestsFromTestCase(PopupWindows)

all_tests = unittest.TestSuite([tests1,tests2])

unittest.TextTestRunner(verbosity=2).run(all_tests)
  • TestLoader().discover can be used to run all of the tests in a directory
  • Selenium WebDriver addons such as HTMLTestRunner can make the Test Suite output pretty
Note that the code of HTMLTestRunner had to be brought upto a 3.4 Python version before it would run
The output looks like:

HTMLTestRunner Output

Hands on Exercise

  • Using Python and PyCharm build a test suite that combines two tests into a suite
Use the tests in the zip file "PyCharm Python and Selenium Projects" at the end of this document

Selenium IDE

  • Selenium IDE works from a simplistic programming language - Selenese
  • In the IDE you can specify Selenese commands
  • With the IDE you can record a session using the Firefox browser
The recording is in Selense, you can then
Run the test case
Modify the recording into the test case
Save the test case as Python
  • The IDE is useful for:
Prototyping
Getting a quick first pass at a test
Trying a prototype and then exporting to WebDriver Python Bindings

Selenese Primer

Record a test case

  • Go to a website that will be the starting point for recording
  • Turn on Recording by clicking the red button at the top right
  • Record a few actions
  • Stop and start recording whenever you want to
  • Build a prototype using some recording and some manual insertion of commands

Recording a Test Case Documentation

Build a test case

  • Open the Selenium IDE
  • First open a Firefox Browser
  • The IDE is an Add-on to the Firefox browser
Install the Add-on if it is not already present
This will give a "Selenium IDE menu item under tools in Firefox
  • Click on the Selenium IDE menu item to open the IDE
  • Commands can be added into the test one at a time
In the command window

Hands on Exercise

  • Open a Firefox browser
  • Open the Selenium IDE (from the Firefox browser)
  • Get the Selenium IDE Testcases Zip File
See the Section at the end of this document called Selenium Sample Zip Files
There is a link to the zip file in that section
  • Extract the Selenium Testcases folder into a well known location
  • In the Selenium IDE open the test called testcase2.html
  • Run this test case and watch the effect in the browser
  • Change the test case so that a different search term is put into Google
  • Run the test and watch the failure
  • Fix the test by choosing a different set of links to go to
Note that you can try getting new links by recording or manually
References
Selenium IDE Documentation
Selenium IDE Command Reference

Selenium Grid

  • Selenium Grid is use to run multiple tests in a distributed environment
The computer controlling the tests is called the hub
The computers being controlled are called the nodes
  • Using a distributed environment allows:
Testing faster depending on the number on nodes used
Note that this is not intended to stress test as you would with a tool like JMeter
For example JMeter slave nodes can simulate between 200 and 800 users per node
Testing with varying operating systems on the various nodes
Testing with varying browsers being used on the various nodes
Testing with various test sets per node

Example of Installing and Running the Grid

The hub and all nodes should have the same Selenium Server version
  • The download is a jar file which will be run using java
Note that you will need to have Java installed on the hub and node computers
It is best to have the same Java version on each computer
The Java JDK (Java Development Kit) is the most useful since it has most tools
It also has the JRE (Java Runtime Environment)
It can be downloaded from Oracle Java Standard Edition (SE)
See the Section in the Contents "Install the Java SE JDK"
  • Place the Selenium Server jar file in a location that is well known
Such as C:\SeleniumServer on Windows
It is best to place the jar files in approximately the same location on each computer
With slight variations caused by the various operating systems
  • Start the hub on the computer where you intend to control the grid
Open a command prompt and move to the directory where the jar file exists
Start the hub using the command java -jar selenium-server-standalone-2.45.0.jar -role hub
The hub by default starts on port 4444

Starting the Grid hub

  • Check that the hub is running using a browser
The Selenium Documentation recommends turning off the Firewall on the hub and nodes
With the Firewall you may get connection errors
Go to URL http://localhost:4444/grid/console or
Click this link once the hub is started Hub Web Interface
The Grid Console runs in a Browser
The Grid Console will look like the following image once the remote host is started and it is refreshed

Selenium Grid Console

  • Check that the node computer can see the hub by doing the same command on the node
Replace the "localhost" with the IP address of the hub
Find the hub IP address using on Windows ipconfig in a command prompt
Look for IPv4 Address

Using ipconfig in a command prompt

  • Start a node computer using the following command:
java -jar selenium-server-standalone-2.45.0.jar -role node -hub http://ipaddressOfHub:4444/grid/register -port 5555
The java -jar tells Java to run the main method within the indicated jar file
The name of the jar file is next selenium-server-stand...
The -role node (can also be webdriver) indicates that this is a node not the hub
The ipaddressOfHub should be the IP address of the computer running the hub
The 4444 is the port that the hub came up on, see the hub command above
The -port 5555 is the port that the node will come up on

Using ipconfig in a command prompt

  • Check that the node has registered by looking at the Hub's grid console
It should look like the prior image and show the connected nodes
Seeing the nodes and their configuration is the consoles main purpose (at this time)
The Hub's configuration can also be seen in the console

Example of a Python UnitTest that is run on the Selenium Grid

  • To get a Python unit test to run on a node it driver code must be changed

The code as run locally is:

class BuildFormsTestCase(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Firefox()
        self.driver.implicitly_wait(30)
        self.base_url = "http://localhost:8080/Web_Project_1/seleniumTest.jsp"
        self.verificationErrors = []
        self.accept_next_alert = True

The changed code to run on a Grid node is:

Note that the IP address and port is the hub location and not the node
The hub determines which node is to be used for the test and transfers the testing on to that node
def setUp(self):
        self.driver = driver = webdriver.Remote(command_executor='http://10.0.0.10:4444/wd/hub', \
                                                desired_capabilities={ \
                                                    "browserName": "firefox", \
                                                    "version": "35", \
                                                    "platform": "VISTA", \
                                                    })

        self.driver.implicitly_wait(30)
        self.base_url = "http://10.0.0.5:8080/Web_Project_1/seleniumTest.jsp"
        self.verificationErrors = []
        self.accept_next_alert = True
  • The command executor tells the location of the hub
  • The hub determines which node will run this set of tests
  • The desired capabilities (platform and browserName) comes from a roll-over of the browser icons in the node's Grid Console entry
For example, for Firefox roll the mouse over the Firefox icons under WebDriver in the console
For some reason the roll over says the platform is VISTA even though the node had Windows 7 in this example
Note that desired capabilities is a dictionary and therefore entries are in that form
  • Once this change is made to the code the code is run on the hub computer
The results (success or failure) come back to the program that is run on the hub
Not to the console window (which might be expected)
  • The test run can be seen in the command prompt on the node computer.
  • The browser window will open and walk through the test on the node computer.
The command window will look similar to the one below as the test is run

Command Prompt on the Grid node

Hands on Exercise

  • Using the instructions above start a hub and a node and run some tests
Use the test files from the Selenium Sample Zip Files section at the end of this document
The zip file to download and extract is under link "PyCharm Python and Selenium Projects"
Use PyCharm and the files in the zipped folder PycharmProjects.zip
Put the unzipped folders inside the PycharmProjects folder into your PycharmProjects folder
Use the buildFormsTestCaseGrid.py file as the test case


References
Official Selenium Grid Documentation
Introduction to Selenium Grid
Selenium Grid

Jenkins with Selenium Grid

References
Jenkins Homepage
Jenkins Selenium Plugin

Move Between Python 2 and 3

The steps to move from Python 3 to Python 2 are:
Download Python 2 and install it
Go to the environment variables and change the path
The path gives the search path for executables
Put python27 in place of python34 in the path
Might be slightly different on a Mac
Run "python setup.py install" in the Selenium Bindings folder
Not that setup.py should be in the folder
The effect is that the Selenium egg will be put into the Python lib
The path to the Selenium egg (on this Windows laptop) is:
C:\Python34\Lib\site-packages\selenium-2.45.0-py3.4.egg

Selenium Sample Zip Files

  • The following zip files are used in the hands on projects in this document
Selenium IDE Testcases Zip File
PyCharm Python and Selenium Projects
Web Project WAR for Tomcat Server with Examples to be Tested

test for boston globe

# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoAlertPresentException
import unittest, time, re

class TopNews(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Firefox()
        self.driver.implicitly_wait(30)
        self.base_url = "http://localhost:8080/"
        self.verificationErrors = []
        self.accept_next_alert = True
    
    def test_top_news(self):
        driver = self.driver
        driver.get("http://www.boston.com/?refresh=true")
        list = driver.find_elements_by_xpath("//ul[@class=\"headline-list__list js-split-list js-add-p1\"]/li[@class=\"headline-list__item\"]/a")
        length = len(list)
        print("the list length is " + str(length))
        for listItem in list:
            print(listItem.get_attribute("href"))
            #print(listItem.getAttribute("href"))
        #driver.get("http://www.boston.com/?refresh=true")
        #driver.find_elements_by_xpath("//ul[@class=\"headline-list__list js-split-list js-add-p1\"]/li[@class=\"headline-list__item\"][2]/a").click()
    
    def is_element_present(self, how, what):
        try: self.driver.find_element(by=how, value=what)
        except NoSuchElementException as e: return False
        return True
    
    def is_alert_present(self):
        try: self.driver.switch_to.alert()
        except NoAlertPresentException as e: return False
        return True
    
    def close_alert_and_get_its_text(self):
        try:
            alert = self.driver.switch_to.alert()
            alert_text = alert.text
            if self.accept_next_alert:
                alert.accept()
            else:
                alert.dismiss()
            return alert_text
        finally: self.accept_next_alert = True
    
    def tearDown(self):
        self.driver.quit()
        self.assertEqual([], self.verificationErrors)

if __name__ == "__main__":
    unittest.main()

Test Automation with Selenium (Java Track)