Skip to content

Instantly share code, notes, and snippets.

@tourdedave
Created February 19, 2014 23:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tourdedave/9103563 to your computer and use it in GitHub Desktop.
Save tourdedave/9103563 to your computer and use it in GitHub Desktop.
Chapter 3 Rendered Example

Writing Your First Selenium Test

Fundamentally, Selenium works with two pieces of information -- the element on a page you want to use and what you want to do with it. This one-two punch will be repeated over and over until you achieve the outcome you want in your application -- at which point you will perform an assertion to confirm that the result is what you intended.

Let's take logging in to a website as an example. With Selenium you would:

  1. Visit the main page of a site
  2. Find the login button and click it
  3. Find the login form's username field and input text
  4. Find the login form's password field and input text
  5. Find the login form and click it

Selenium is able to find and interact with elements on a page by way of various locator strategies. The list includes Class, CSS, ID, Link Text, Name, Partial Link Text, Tag Name, and XPath.

While each serves a purpose, you only need to know a few to start writing effective tests.

How To Find Locators

The simplest way to find locators is to inspect the elements on a page. The best way to do this is from within your web browser. Fortunately, popular browsers come pre-loaded with development tools that make this simple to accomplish.

When viewing the page, right-click on the element you want to interact with and click Inspect Element. This will bring up a small window with all of the HTML for the page but zoomed into your highlighted selection. From here you can see if there are unique or descriptive attributes you can work with.

How To Find Quality Elements

Your focus with picking an effective element should be on finding something that is unique, descriptive, and unlikely to change. Ripe candidates for this are id and class attributes. Whereas copy (e.g., text, or the text of a link) is less ideal since it is more apt to change. This may not hold true for when you make assertions, but it's a good goal to strive for.

If the elements you are attempting to work with don't have unique id or class attributes directly on them, look at the element that houses them (a.k.a. the parent element). Oftentimes the parent element has a unique locator that you can use to start with and drill down into the element you want to use (with CSS selectors).

And if you can't find any unique elements, have a conversation with your development team letting them know what you are trying to accomplish. It's not hard for them to add helpful, semantic markup to make test automation easier, especially when they know the use case you are trying to automate. The alternative can be a lengthy, painful process which will probably yield working test code -- but it will be brittle and hard to maintain.

Steps To Writing a Selenium Test

There are five parts to writing a Selenium test:

  1. Find the elements you want to use
  2. Write a test with Selenium actions that use these elements
  3. Figure out what to assert
  4. Write the assertion and verify it
  5. Double-check the assertion by forcing it to fail

As part of writing your Selenium test, you will also need to create and destroy a browser instance. This is something that we will pull out of our tests in a future lesson, but it's worth knowing about up front.

Let's take our login example from above and step through the test writing process.

An Example

The best way to find the Selenium actions for your specific language is to look at the available language binding wiki pages (Ruby, Python, JavaScript) or the Selenium HQ getting started documentation for WebDriver.

For this example, I'll be using the Ruby programming language, RSpec (an open-source testing framework written in Ruby), and the-internet (an open-source example application I built).

1. Find the elements you want to use

Let's use the login example on the-internet). Here's the markup from the page.

<form name="login" id="login" action="/authenticate" method="post">
   <div class="row">
    <div class="large-6 small-12 columns">
      <label for="username">Username</label>
      <input type="text" name="username" id="username">
    </div>
  </div>
  <div class="row">
    <div class="large-6 small-12 columns">
      <label for="password">Password</label>
      <input type="password" name="password" id="password">
    </div>
  </div>
    <button class="radius" type="submit"><i class="icon-2x icon-signin"> Login</i></button>
</form>

Note the unique elements on the form. The username input field has a unique id, as does the password input field. The submit button doesn't, but the parent element (form) does. So instead of clicking the submit button, we will have to submit the form instead.

Let's put these elements to use in our first test (or 'spec' as it's called in RSpec).

2. Write a test with Selenium actions that use these elements

# filename: login_spec.rb

require 'selenium-webdriver'

describe 'Login' do

  before(:each) do
    @driver = Selenium::WebDriver.for :firefox
  end

  after(:each) do
    @driver.quit
  end

  it 'succeeded' do
    @driver.get 'http://the-internet.herokuapp.com/login'
    @driver.find_element(id: 'username').send_keys('tomsmith')
    @driver.find_element(id: 'password').send_keys('SuperSecretPassword!')
    @driver.find_element(id: 'login').submit
  end

end

If we run this (e.g., rspec login_spec.rb from the command-line), it will run and pass. But there's one thing missing -- an assertion. In order to find an element to make an assertion against, we need to see what the markup is after submitting the login form.

3. Figure out what to assert

Here is the markup that renders on the page after submitting the login form.

<div class="row">
  <div id="flash-messages" class="large-12 columns">
    <div data-alert="" id="flash" class="flash success">
      You logged into a secure area!
      <a href="#" class="close">x</a>
    </div>
  </div>
</div>

<div id="content" class="large-12 columns">
  <div class="example">
    <h2><i class="icon-lock"></i> Secure Area</h2>
    <h4 class="subheader">Welcome to the Secure Area. When you are done click logout below.</h4>
    <a class="button secondary radius" href="/logout"><i class="icon-2x icon-signout"> Logout</i></a>
  </div>
</div>

After logging in, there looks to be a couple of things we can key off of for our assertion. There's the flash message class (most appealing), the logout button (appealing), or the copy from the h2 or the flash message (least appealing).

Since the flash message class name is descriptive, denotes success, and is less likely to change than the copy, let's go with that.

4. Write the assertion and verify it

# filename: login_spec.rb

require 'selenium-webdriver'

describe 'Login' do

  before(:each) do
    @driver = Selenium::WebDriver.for :firefox
  end

  after(:each) do
    @driver.quit
  end

  it 'successful' do
    @driver.get 'http://the-internet.herokuapp.com/login'
    @driver.find_element(id: 'username').send_keys('username')
    @driver.find_element(id: 'password').send_keys('password')
    @driver.find_element(id: 'login').submit
    @driver.find_element(css: '.flash.success').displayed?.should be_true
  end

end

5. Double-check the assertion by forcing it to fail

Now when we run this test (rspec login_spec.rb from the command-line) it will pass just like before, but now there is an assertion which should catch a failure if something is amiss.

Just to make certain that this test is doing what we think it should, let's change the assertion to force a failure and run it again. A simple fudging of the locator will suffice.

@driver.find_element(css: '.flash.successasdf').displayed?.should be_true

If it fails, then we can feel confident that it's doing what we expect, and can change the assertion back to normal before committing our code. This trick will save you more trouble that you know. Practice it often.

For more examples like this (and a whole lot more), check out my book -- The Selenium Guidebook.

Up next, I'll cover how to structure your test code to make it reusable and simple to maintain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment