Using Python Selenium with Pytest and SauceLabs

Assuming that you have an account at SauceLabs and that you have exported your credentials via your system’s environmental variables, let’s re-create those same automated tests and execute them on SauceLabs:

Use Cases

  • As a user, when I open www.google.com on my web browser, the web browser tab will show the word Google as its title
  • As a user, when I open www.google.com on my web browser and search for the word Red Hat, the web browser tab will show the word Red Hat as its title

Python Code

Here is the Python code that will automate these tests:

Fixtures

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
import pytest


BROWSERS = [
        {
            'browserName': 'chrome',
            'platform': 'macOS 10.12',
        },
        {
            'browserName': 'MicrosoftEdge',
            'platform': 'Windows 10',
        },
        {
            'browserName': 'firefox',
            'platform': 'Linux',
        },
        {
            'browserName': 'safari',
            'platform': 'macOS 10.12',
        },
]


def pytest_addoption(parser):
    """Add command line option to select webdriver capabilities.
    These options can be used to choose the webdriver capabilites
    as such:
    browser_name = request.config.getoption('--webdriver')
    """
    parser.addoption(
        '--browsername',
        action="store",
        default='firefox',
        choices=['chrome', 'firefox', 'safari', 'Android', 'MicrosoftEdge'],
        help="Specify the web browser to use for the automation."
    )
    parser.addoption(
        '--platform',
        action="store",
        default='macOS 10.12',
        choices=['macOS 10.12', 'Windows 10', 'Linux'],
        help="Specify the platform to use for the automation."
    )


def test_id(fixture_value):
    """Return a human readable ID for a parameterized fixture."""
    return '{browserName}'.format(**fixture_value)


@pytest.fixture(
    params=BROWSERS,
    ids=test_id,
    )
def capabilities(request, capabilities):
    """Used to pass arguments to SauceLabs."""
    capabilities['build'] = (
        'Web UI Automation with Selenium for Beginners'
        )
    capabilities['acceptSslCerts'] = True
    capabilities['javascriptEnabled'] = True
    capabilities.update(request.param)
    return capabilities


@pytest.fixture(
    scope='function',
)
def browser(request, selenium):
    """Fixture to create a web browser."""
    def close_browser():
        """Handle closing browser object."""
        selenium.quit()

    def update_saucelabs():
        """Add build info for easy viewing on SauceLabs."""
        selenium.execute_script(
            "sauce:job-result={}".format(
                str(not request.node.rep_call.failed).lower()))
        selenium.execute_script(
            "sauce:job-name={}".format(request.node.rep_call.nodeid))

    request.addfinalizer(update_saucelabs)
    request.addfinalizer(close_browser)

    return selenium


@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
    # this sets the result as a test attribute for SauceLabs reporting.
    # execute all other hooks to obtain the report object
    #
    # Borrowed from https://github.com/saucelabs-sample-test-frameworks/
    #                       Python-Pytest-Selenium/blob/master/conftest.py
    outcome = yield
    rep = outcome.get_result()

    # set a report attribute for each phase of a call, which can
    # be "setup", "call", "teardown"
    setattr(item, "rep_" + rep.when, rep)

Tests

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
from selenium.webdriver.common.keys import Keys


def test_page_title(browser):
    """Assert that title of page says 'Google'."""
    browser.get('http://www.google.com')
    assert 'Google' in browser.title


def test_search_page_title(browser):
    """Assert that Google search returns data for 'Red Hat'."""
    browser.implicitly_wait(10)
    browser.get('http://www.google.com')
    assert 'Google' in browser.title
    element = browser.find_element_by_id('lst-ib')
    assert element is not None
    element.send_keys('Red Hat' + Keys.RETURN)
    assert browser.title.startswith('Red Hat')

Now we can execute these tests:

pytest -v -n 2 --driver SauceLabs tests/saucelabs/test_SeleniumSauce.py -k test_page_title
============================================================================================= test session starts =============================================================================================
platform darwin -- Python 3.7.0, pytest-3.6.4, py-1.5.4, pluggy-0.6.0 -- /Users/omaciel/.virtualenvs/devconfusa18/bin/python
cachedir: .pytest_cache
driver: SauceLabs
sensitiveurl: .*
metadata: {'Python': '3.7.0', 'Platform': 'Darwin-17.7.0-x86_64-i386-64bit', 'Packages': {'pytest': '3.6.4', 'py': '1.5.4', 'pluggy': '0.6.0'}, 'Plugins': {'xdist': '1.22.5', 'variables': '1.7.1', 'selenium': '1.13.0', 'metadata': '1.7.0', 'html': '1.19.0', 'forked': '0.2', 'base-url': '1.4.1'}, 'Base URL': '', 'Driver': 'SauceLabs', 'Capabilities': {}}
rootdir: /Users/omaciel/hacking/devconfusa18, inifile:
plugins: xdist-1.22.5, variables-1.7.1, selenium-1.13.0, metadata-1.7.0, html-1.19.0, forked-0.2, base-url-1.4.1
[gw0] darwin Python 3.7.0 cwd: /Users/omaciel/hacking/devconfusa18
[gw1] darwin Python 3.7.0 cwd: /Users/omaciel/hacking/devconfusa18
[gw0] Python 3.7.0 (default, Jun 29 2018, 20:13:13)  -- [Clang 9.1.0 (clang-902.0.39.2)]
[gw1] Python 3.7.0 (default, Jun 29 2018, 20:13:13)  -- [Clang 9.1.0 (clang-902.0.39.2)]
gw0 [4] / gw1 [4]
scheduling tests via LoadScheduling

tests/saucelabs/test_SeleniumSauce.py::test_page_title[chrome]
tests/saucelabs/test_SeleniumSauce.py::test_page_title[MicrosoftEdge]
[gw0] [ 25%] PASSED tests/saucelabs/test_SeleniumSauce.py::test_page_title[chrome]
tests/saucelabs/test_SeleniumSauce.py::test_page_title[firefox]
[gw0] [ 50%] PASSED tests/saucelabs/test_SeleniumSauce.py::test_page_title[firefox]
[gw1] [ 75%] PASSED tests/saucelabs/test_SeleniumSauce.py::test_page_title[MicrosoftEdge]
tests/saucelabs/test_SeleniumSauce.py::test_page_title[safari]
[gw1] [100%] PASSED tests/saucelabs/test_SeleniumSauce.py::test_page_title[safari]

========================================================================================== 4 passed in 63.22 seconds ==========================================================================================
_images/saucelabs-dashboard.png