Package: questions-three-selenium
Selenium Integrations for Questions ThreeThis document assumes you are familiar with bothQuestions ThreeandSelenium WebDriverand are interested in putting them together to build beautiful Web UI checks.FeaturesExtended WebDriver class (Browser)Does everything that WebDriver canAutomatically publishes a screen shot and a DOM dump for each test failureProvides extra "find" methods with a more pythonic syntaxCan place artifacts in local (HTML 5) storageCan detect navigation to a new pageWaterproof, as used in hospitalsSupport for remote browsersBrowserStackSelenium GridA trivial exampleThis example assumes that you have Chrome andChromedriverinstalled locally.  Chrome is the default browser but Firefox is also supported.  SeeControlling behavior with environment variables.pip install questions-three-seleniumtrivial_example.pyfrom expects import expect, contain
from questions_three.scaffolds.test_script import test, test_suite
from questions_three_selenium.browser.browser import Browser

with test_suite('SeleniumExample'):

    browser = Browser()
    browser.get('http://www.example.com')

    # This test will probably pass
    with test('Verify text contains example domain'):
        html = browser.find_unique_element(tag_name='html')
        expect(html.text.lower()).to(contain('example domain'))

    # This test should fail unless the Spinach Inquisition takes over example.com
    with test('Verify text contains Cardinal Biggles'):
        html = browser.find_unique_element(tag_name='html')
        expect(html.text.lower()).to(contain('Cardinal Biggles'))python3 trivial_example.pyThe example includes a failing case so you can inspect thereportsdirectory and see the artifacts that get saved when something fails.Controlling behavior with environment variablesBROWSER_LOCATIONSet this to "local" to use a local browserSet it to "browserstack" to use a remote browser via BrowserStackSet it to "selenium_grid" to use a remote browser via Selenium GridUSE_BROWSERSet this to "chrome" to use ChromeSet it to "firefox" to use FirefoxUSE_BROWSER_VERSIONRequest this version of the browser.  Applies only to remotes.CHROME_USER_AGENTIf using Chrome, pretend to be some other browser by hacking the user agent string to this.BROWSER_AVAILABILITY_TIMEOUTWait up to this number of seconds for a browser to become availableBROWSER_ELEMENT_FIND_TIMEOUTWait up to this number of seconds for a requested element to appear in the DOMSUPPRESS_BROWSER_EXIT_ON_FAILUREOrdinarily, the browser will close automatically when the test suite ends.  Set this to "true" to leave the browser open after something breaks.  Useful for debugging.Browser objectsThe trivial example launches a web browser by instantiating aBrowserobject.Browseris mostly a wrapper aroundselenium.webdriver.[browser name].webdriver.WebDriver.It can behave like an ordinary WebDriver objectBrowserobjects can do anything that the underlyingWebDrivercan do, as documented inSelenium with Python.Here is the simple example from the Selenium documentation, modified to useBrowser:from questions_three_selenium import Browser
from selenium.webdriver.common.keys import Keys

driver = Browser()
driver.get("http://www.python.org")
assert "Python" in driver.title
elem = driver.find_element_by_name("q")
elem.clear()
elem.send_keys("pycon")
elem.send_keys(Keys.RETURN)
assert "No results found." not in driver.page_source
driver.close()The example callsdriver.close()but, when you instantiate aBrowserinside a Questions Three suite, it will close automatically after the suite ends.Artifact publishingBrowseris capable of producing a screen shot or a DOM dump (human-readable HTML file that shows all elements in the DOM at some point in time).Manual generationMost of the time, you won't need to do this becauseBrowserautomatically publishes artifacts when a failure occurs, but it's possible:from questions_three_selenium.dom_dumper.dump_dom import dump_dom

browser = Browser()
browser.get('http://www.example.com/')

html_string = dump_dom(browser)
screenshot_png_bytes = browser.get_screenshot_as_png()
# Use your imagination.  Do something creative with your artifacts.Automatic publishingBottom line: you'll see a DOM dump and a screen shot in thereportsdirectory for each test that fails.  Read on if you would like to understand how this works.At its core, Questions Three isevent-driven.  When something goes wrong, the scaffold publishes the appropriate event (SUITE_ERRED,TEST_ERRED, orTEST_FAILED).Browsersubscribes to all three. When any of these events occurs, it does the following:Take a screen shot of itselfPublish the screen shot as anARTIFACT_CREATEDeventTake a DOM dump of itselfPublish the DOM dump as anARTIFACT_CREATEDeventBy default, Questions Three activates a reporter calledArtifactSaver.  It subscribes toARTIFACT_CREATEDevents and saves each artifact to the appropriate place underreports.Extra find methodsaBrowserinstance can be used just like an ordinaryWebDriverinstance.  For the sake of convenience and readability, it offers alternative methods for finding elements.pythonic syntaxThe extra methods accept locators as keyword arguments, so instead of thisbrowser.find_elements(By.LINK_TEXT, 'Finland')you can write this:browser.find_all_matching_elements(link_text='Finland')All selectors defined byselenium.webdriver.common.byare supported.find_all_matching_elementsReturns a list of all elements that match the given keyword.  If no elements match, returns an empty list.divs = browser.find_all_matching_elements(tag_name='div')
bobs = browser.find_all_matching_elements(id='bob')find_unique_elementExpects the given keyword argument to match exactly one element in the DOM.
If the expectation is met, returns the element.
If if no element matches, raises NoSuchElement.
If more than one element matches, raises TooManyElements.great_sorcerer = browser.find_unique_element(id='tim?')Detecting navigation to a new pagefrom questions_three.vanilla import wait_for
from questions_three_selenium import Browser

browser = Browser()
browser.get('http://www.example.com/magic_page')
are_we_there_yet = browser.func_that_detects_new_page()
browser.find_unique_element(id='magic_button').click()
wait_for(are_we_there_yet, timeout=20, throttle=1)Writing to HTML 5 local storageSome web applications uselocal storageinstead of cookies for storing things like session tokens.Browserprovides a convenience method for writing to it.session = log_in(username='ximinez', password='N0b0dyExpects')
browser.add_to_local_storage(key='session_token', value=session)BrowserStack supportTyingBrowserto a fresh remote browser fromBrowserStackis a simple matter of setting some environment variables -- unless you also want to use their"Local"tunnel.  More on that in a bit.For best results, visit BrowserStack'sCapabilitiespage and play with the available configurations.  Each of the capabilities maps to an environment variable for Questions Three Selenium:CapabilityEnvironment Variable NameosBROWSERSTACK_OSos_versionBROWSERSTACK_OS_VERSIONbrowserUSE_BROWSERbrowser_versionUSE_BROWSER_VERSIONOther required environment variables:BROWSER_LOCATIONSet this to "browserstack"BROWSERSTACK_USERNAMESet this to the username associated with the BrowserStack accountBROWSERSTACK_ACCESS_KEYSet this to the access key provided by BrowserStack for automationOptional environment variables:BROWSERSTACK_SCREEN_RESOLUTIONSet this to one of the strings under "resolution" on theCapabilities pageBROWSERSTACK_SET_DEBUGSet this to "true" or "false."  It defaults to "false."With those environment variables set, instantiate aBrowserobject as normal and it will launch a remote browser via BrowserStack."Local" tunnelThe tunnel requires an executable binary provided by BrowserStack. The BrowserStack integration expects this binary to be in a zip archive at some URL.  For best performance, this URL should refer to a nearby location that you control.Required environment variables:BROWSERSTACK_SET_LOCALSet this to "true"BROWSERSTACK_LOCAL_BINARY_ZIP_URLThis defaults to the Linux x64 binary at BrowserStack.  Point it to wherever you have a zip archive of the binary.BROWSERSTACK_LOCAL_BINARYFull path and filename to where the binary should be stored locally.  Default:/tmp/browserstack_tunnel/BrowserStackLocalBROWSERSTACK_URLURL to the BrowserStack hub. Default:http://hub.browserstack.com/wd/hubOptional environment variables:BROWSERSTACK_TUNNEL_TIMEOUTWait up to this number of seconds for the tunnel to open. Default: 30.Selenium Grid supportSelenium Gridsupport is a simple matter of setting environment variables and then instantiating aBrowserobject normally.Required environment variables:BROWSER_LOCATIONSet this to "selenium_grid"USE_BROWSERSet this to the name of the expected browser (e.g. "Firefox").  The exact names will vary with Grid configuration.SELENIUM_GRID_HUB_URLSet this to the URL of your hubOptional environment variables:USE_BROWSER_VERSIONAuthoritative list of environment variablesSeemodule_cfg.yml