Kensuke Kousaka's Blog

Notes for Developing Software, Service.

Web UI testing using Selenium, PhantomJS, and nose

You can easily test UI if you use Selenium (UI test tools), PhantomJS (Headless browser), and nose (Unit testing library).

Install Selenium and PhantomJS

Install Selenium and PhantomJS by running following command.

$ pip install selenium

Install PhantomJS from OS packaging system (e.g. Use Homebrew for macOS).

$ brew install phantomjs

Flask Web app UI testing using nose, Selenium, PhantomJS

Use k3nsuk3/HelloFlask which using Flask, Python based Web application framework, for UI testing. This app run from app.py and show login page when access to http://127.0.0.1:8080 through Web browser.

Click Sign in button to show login modal, input user name as admin and password as some string, and click Sign in button to login. After login, input some uppercase string and click Change text button so that text is converted to lowercase and show it.

In this time, test these functions working correctly or not by UI side. Directory structure is like following.

- HelloFlask/
    - FlaskApp/
        - app.py
        - static/
            - css/
                - sample.css
            - js/
                - sample.js
        - templates/
            - index.html
            - login.html
        - Tests/
            - test_access.py
            - test_ui.py

In this article, write UI test code to test_ui.py.

Import libraries to use UI testing

Write import codes to use UI testing libraries before writing test codes.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
from nose.tools import eq_

In this codes, import Selenium web driver and nose.

Access to root URL

Test to access to app route url and redirect to login page correctly. Implement by following.

def test_access():
    driver = webdriver.PhantomJS('/PATH/TO/phantomjs')
    wait = WebDriverWait(driver, 5)

    driver.get('http://127.0.0.1:8080/')
    wait.until(ec.presence_of_all_elements_located)
    eq_('http://127.0.0.1:8080/login', driver.current_url)
    driver.close()

driver.get('http://127.0.0.1:8080/') to access to app route url. After all elements located, eq_('http://127.0.0.1:8080/login', driver.current_url) to check current page is login page or not (to check redirected).

Login (Failure)

Click Sign in button to show login modal, and fail to login intentionally to check redirect to login page correctly.

def test_fail_login():
    driver = webdriver.PhantomJS('/PATH/TO/phantomjs')
    wait = WebDriverWait(driver, 5)

    driver.get('http://127.0.0.1:8080/')
    wait.until(ec.presence_of_all_elements_located)
    eq_('http://127.0.0.1:8080/login', driver.current_url)

    show_signin = driver.find_element_by_id('showSignIn')
    show_signin.click()

    wait.until(ec.visibility_of_element_located(By.ID, 'username'))
    username = driver.find_element_by_id('username')
    username.send_keys('test')

    wait.until(ec.visibility_of_element_located(By.ID, 'password'))
    password = driver.find_element_by_id('password')
    password.send_keys('test')'

    wait.until(ec.visibility_of_element_located(By.ID, "signIn'))
    signin = driver.find_element_by_id('signIn')
    signin.click()

    wait.until(ec.presence_of_all_elements_located)
    eq_('http://127.0.0.1:8080/login', driver.current_url)
    driver.close()

Get Sign in button by show_signin = driver.find_element_by_id('showSignIn') and click this button by show_signin.click() to show login modal. Wait until completely showing login modal by wait.until(ec.visibility_of_element_located(By.ID, 'username')). Input text to form by username.send_keys('test') and password.send_keys('test'), and signin.click() to click Sign in button to try login.

If authentication system working correctly, this login is fail and redirect to login page so that test it by eq_('http://127.0.0.1:8080/login', driver.current_url).

Login (Success)

Next, input proper user name and password, and check to access to top page correctly when succeed to login.

def test_success_login():
    driver = webdriver.PhantomJS('/PATH/TO/phantomjs')
    wait = WebDriverWait(driver, 5)

    driver.get('http://127.0.0.1:8080/')
    wait.until(ec.presence_of_all_elements_located)
    eq_('http://127.0.0.1:8080/login', driver.current_url)

    show_signin = driver.find_element_by_id('showSignIn')
    show_signin.click()

    wait.until(ec.visibility_of_element_located(By.ID, 'username'))
    username = driver.find_element_by_id('username')
    username.send_keys('admin')

    wait.until(ec.visibility_of_element_located(By.ID, 'password'))
    password = driver.find_element_by_id('password')
    password.send_keys('test')

    wait.until(ec.visibility_of_element_located(By.ID, 'signIn'))
    signin = driver.find_element_by_id('signIn')
    signin.click()

    wait.until(ec.presence_of_all_elements_located)
    eq_('http://127.0.0.1:8080/', driver.current_url)

    logout = driver.find_element_by_id('logout')
    logout.click()

    wait.until(ec.presence_of_all_elements_located)
    eq_('http://127.0.0.1:8080/login', driver.current_url)
    driver.close()

This test code input proper user name and password so that succeed to login and should move to root url, so test it by eq_('http://127.0.0.1:8080/', driver.current_url). And also test logout function by eq_('http://127.0.0.1:8080/login', driver.current_url).

Convert from Uppercase to Lowercase

Test for Uppercase -> Lowercase conversion.

def test_lower_conversion():
    driver = webdriver.PhantomJS('/PATH/TO/phantomjs')
    wait = WebDriverWait(driver, 5)

    driver.get('http://127.0.0.1:8080/')
    wait.until(ec.presence_of_all_elements_located)
    eq_('http://127.0.0.1:8080/login', driver.current_url)

    show_signin = driver.find_element_by_id('showSignIn')
    show_signin.click()

    wait.until(ec.visibility_of_element_located(By.ID, 'username'))
    username = driver.find_element_by_id('username')
    username.send_keys('admin')

    wait.until(ec.visibility_of_element_located(By.ID, 'password'))
    password = driver.find_element_by_id('password')
    password.send_keys('test')

    wait.until(ec.visibility_of_element_located(By.ID, 'signIn'))
    signin = driver.find_element_by_id('signIn')
    signin.click()

    wait.until(ec.presence_of_all_elements_located)
    eq_('http://127.0.0.1:8080/', driver.current_url)

    input_text = driver.find_element_by_id('input-text')
    input_text.send_keys('TEST')

    change_text = driver.find_element_by_id('button')
    change_text.click()

    wait.until(ec.presence_of_all_elements_located)
    hello = driver.find_element_by_id('hello')
    eq_('test', hello.text)

    logout = driver.find_element_by_id('logout')
    logout.click()

    wait.until(ec.presence_of_all_elements_located)
    eq_('http://127.0.0.1:8080/login', driver.current_url)
    driver.close()

Input TEST into textbox and click Change text button, and check converted text equals to test.

UI testing

Before testing you need to run application to test. Move current directory to FlaskApp and run following command to run app.

$ python app.py

After app running, run following command to begin test.

$ nosetests

This sample app is published at k3nsuk3/HelloFlask