2013-07-08

PhantomJS is a headless Webkit, which has a number of uses. In this example, we will be using it, in conjunction with Selenium WebDriver, for conducting unit tests directly from the command line. Since PhantomJS eliminates the need for a graphical browser, tests run much faster.

Click here to watch the accompanying video.


Setup

  1. Install Selenium

    pip install selenium
    
  2. Then install PhantomJS with Brew:

    brew install phantomjs
    

    Or you can grab the latest build here.

Examples

Now let's look at two quick examples.

DuckDuckGo

In the first, I'm just going to search DuckDuckGo for the keyword "realpython" to find the URL of the search results.

from selenium import webdriver
driver = webdriver.PhantomJS()
driver.get("http://duckduckgo.com/")
driver.find_element_by_id('search_form_input_homepage').send_keys("realpython")
driver.find_element_by_id("search_button_homepage").click()
print driver.current_url
driver.quit

You can see the outputted URL on the terminal.

Then here's a look at the same thing using a Firefox to display the results.

from selenium import webdriver
driver = webdriver.Firefox()
driver.get("http://duckduckgo.com/")
driver.find_element_by_id('search_form_input_homepage').send_keys("realpython")
driver.find_element_by_id("search_button_homepage").click()
driver.quit

Now I can write a quick unit test to assert that the URL brought up by the search results is correct.

import unittest
from selenium import webdriver
class TestOne(unittest.TestCase):

    def setUp(self):
        self.driver = webdriver.PhantomJS()

    def test_url(self):
        self.driver.get("http://duckduckgo.com/")
        self.driver.find_element_by_id('search_form_input_homepage').send_keys("realpython")
        self.driver.find_element_by_id("search_button_homepage").click()
        self.assertIn("https://duckduckgo.com/?q=realpython", self.driver.current_url)

    def tearDown(self):
        self.driver.quit

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

As you can tell the test passed.

RealPython.com

Finally, let's look at a real world example that I run daily with Jenkins. Let's go to RealPython.com and I'll show you what I will be testing. Essentially, I want to ensure that the Buy Now popup is for the correct product.

Here's a look at the basic unittest:

import unittest
from selenium import webdriver
class TestTwo(unittest.TestCase):

    def setUp(self):
        self.driver = webdriver.PhantomJS()

    def test_url(self):
        self.driver.get("http://www.realpython.com/")
        self.driver.find_element_by_class_name("simple-goods-btn").click()
        self.driver.switch_to_frame(1) 
        self.assertIn("https://www.simplegoods.co/embed/XDGLSALS", self.driver.current_url)

    def tearDown(self):
        self.driver.quit

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

Benchmarking

One main advantage of using PhantomJS over a browser is that tests are much faster. In this next example I benchmarked the previous test using both PhantomJS and Firefox.

import unittest
from selenium import webdriver
import time
class TestThree(unittest.TestCase):

    def setUp(self):
        self.startTime = time.time()

    def test_url_fire(self):
        time.sleep(2)
        self.driver = webdriver.Firefox()
        self.driver.get("http://www.realpython.com/")
        self.driver.find_element_by_class_name("simple-goods-btn").click()
        self.driver.switch_to_frame(1) 
        self.assertIn("https://www.simplegoods.co/embed/XDGLSALS", self.driver.current_url)

    def test_url_phantom(self):
        time.sleep(1)
        self.driver = webdriver.PhantomJS()
        self.driver.get("http://www.realpython.com/")
        self.driver.find_element_by_class_name("simple-goods-btn").click()
        self.driver.switch_to_frame(1) 
        self.assertIn("https://www.simplegoods.co/embed/XDGLSALS", self.driver.current_url)

    def tearDown(self):
        t = time.time() - self.startTime
        print "%s: %.3f" % (self.id(), t)
        self.driver.quit

if __name__ == '__main__':
    suite = unittest.TestLoader().loadTestsFromTestCase(TestThree)
    unittest.TextTestRunner(verbosity=0).run(suite)

You can see just how much faster PhantomJS is:

image



Video



Want to learn more? Download the Real Python course.

Download Now ยป $60

Or, click here to learn more about the course.



blog comments powered by Disqus