Use environment variables to configure Selenium remote WebDriver. For use with SauceLabs (via SauceConnect) or local browsers.
bok_choy.browser.
BrowserConfigError
[source]¶Misconfiguration error in the environment variables.
bok_choy.browser.
add_profile_customizer
(func)[source]¶Add a new function that modifies the preferences of the firefox profile object it receives as an argument
bok_choy.browser.
browser
(tags=None, proxy=None, other_caps=None)[source]¶Interpret environment variables to configure Selenium. Performs validation, logging, and sensible defaults.
There are three cases:
then we use a local browser.
the ones needed for SauceLabs:
SauceLabs: Set all of the following environment variables:
- SELENIUM_BROWSER
- SELENIUM_VERSION
- SELENIUM_PLATFORM
- SELENIUM_HOST
- SELENIUM_PORT
- SAUCE_USER_NAME
- SAUCE_API_KEY
NOTE: these are the environment variables set by the SauceLabs Jenkins plugin.
Optionally provide Jenkins info, used to identify jobs to Sauce:
- JOB_NAME
- BUILD_NUMBER
tags is a list of string tags to apply to the SauceLabs job. If not using SauceLabs, these will be ignored.
Keyword Arguments: | |
---|---|
|
|
Returns: | The configured browser object used to drive tests |
Return type: | selenium.webdriver |
Raises: |
|
bok_choy.browser.
clear_profile_customizers
()[source]¶Remove any previously-configured functions for customizing the firefox profile
bok_choy.browser.
save_driver_logs
(driver, prefix)[source]¶Save the selenium driver logs.
The location of the driver log files can be configured by the environment variable SELENIUM_DRIVER_LOG_DIR. If not set, this defaults to the current working directory.
Parameters: |
|
---|---|
Returns: | None |
bok_choy.browser.
save_screenshot
(driver, name)[source]¶Save a screenshot of the browser.
The location of the screenshot can be configured by the environment variable SCREENSHOT_DIR. If not set, this defaults to the current working directory.
Parameters: |
|
---|---|
Returns: | None |
bok_choy.browser.
save_source
(driver, name)[source]¶Save the rendered HTML of the browser.
The location of the source can be configured by the environment variable SAVED_SOURCE_DIR. If not set, this defaults to the current working directory.
Parameters: |
|
---|---|
Returns: | None |
Helpers for dealing with JavaScript synchronization issues.
bok_choy.javascript.
js_defined
(*js_vars)[source]¶Class decorator that ensures JavaScript variables are defined in the browser.
This adds a wait_for_js method to the class, which will block until all the expected JavaScript variables are defined.
Parameters: | js_vars (list of str) – List of JavaScript variable names to wait for. |
---|---|
Returns: | Decorated class |
Base implementation of the Page Object pattern. See https://github.com/SeleniumHQ/selenium/wiki/PageObjects and http://www.seleniumhq.org/docs/06_test_design_considerations.jsp#page-object-design-pattern
bok_choy.page_object.
PageObject
(browser, *args, **kwargs)[source]¶Encapsulates user interactions with a specific part of a web application.
The most important thing is this: Page objects encapsulate Selenium.
If you find yourself writing CSS selectors in tests, manipulating forms, or otherwise interacting directly with the web UI, stop!
Instead, put these in a PageObject
subclass :)
PageObjects do their best to verify that they are only
used when the browser is on a page containing the object.
To do this, they will call is_browser_on_page()
before executing
any of their methods, and raise a WrongPageError
if the
browser isn’t on the correct page.
Generally, this is the right behavior. However, at times it
will be useful to not verify the page before executing a method.
In those cases, the method can be marked with the unguarded()
decorator. Additionally, private methods (those beginning with _)
are always unguarded.
Class or instance properties are never guarded. However, methods
marked with the property()
are candidates for being guarded.
To make them unguarded, you must mark the getter, setter, and deleter
as unguarded()
separately, and those decorators must be applied before
the property()
decorator.
Correct:
@property
@unguarded
def foo(self):
return self._foo
Incorrect:
@unguarded
@property
def foo(self):
return self._foo
Initialize the page object to use the specified browser instance.
Parameters: | browser (selenium.webdriver) – The Selenium-controlled browser. |
---|---|
Returns: | PageObject |
handle_alert
(*args, **kwargs)[source]¶Context manager that ensures alerts are dismissed.
Example usage:
with self.handle_alert():
self.q(css='input.submit-button').first.click()
Keyword Arguments: | |
---|---|
confirm (bool) – Whether to confirm or cancel the alert. | |
Returns: | None |
is_browser_on_page
()[source]¶Check that we are on the right page in the browser. The specific check will vary from page to page, but usually this amounts to checking the:
- browser URL
- page title
- page headings
Returns: | A bool indicating whether the browser is on the correct page. |
---|
q
(**kwargs)[source]¶Construct a query on the browser.
Example usages:
self.q(css="div.foo").first.click()
self.q(xpath="/foo/bar").text
Keyword Arguments: | |
---|---|
|
|
Returns: | BrowserQuery |
scroll_to_element
(element_selector, timeout=60)[source]¶Scrolls the browser such that the element specified appears at the top. Before scrolling, waits for the element to be present.
Example usage:
self.scroll_to_element('.far-down', 'Scroll to far-down')
Parameters: |
|
---|
Raises: BrokenPromise if the element does not exist (and therefore scrolling to it is not possible)
url
¶Return the URL of the page. This may be dynamic, determined by configuration options passed to the page object’s constructor.
Some pages may not be directly accessible: perhaps the page object represents a “navigation” component that occurs on multiple pages. If this is the case, subclasses can return None to indicate that you can’t directly visit the page object.
validate_url
(url)[source]¶Return a boolean indicating whether the URL has a protocol and hostname. If a port is specified, ensure it is an integer.
Parameters: | url (str) – The URL to check. |
---|---|
Returns: | Boolean indicating whether the URL has a protocol and hostname. |
visit
()[source]¶Open the page containing this page object in the browser.
Some page objects may not provide a URL, in which case a NotImplementedError will be raised.
Raises: |
|
---|---|
Returns: | PageObject |
wait_for
(promise_check_func, description, result=False, timeout=60)[source]¶Calls the method provided as an argument until the Promise satisfied or BrokenPromise. Retries if a WebDriverException is encountered (until the timeout is reached).
Parameters: |
|
---|---|
Raises: |
|
wait_for_ajax
(timeout=30)[source]¶Wait for jQuery to be loaded and for all ajax requests to finish. Note that we have to wait for jQuery to load first because it is used to check that ajax requests are complete.
Important: If you have an ajax requests that results in a page reload, you will need to use wait_for_page or some other method to confirm that the page has finished reloading after wait_for_ajax has returned.
Example usage:
self.q(css='input#email').fill("foo")
self.wait_for_ajax()
Keyword Arguments: | |
---|---|
|
|
Returns: | None |
Raises: |
|
wait_for_element_absence
(element_selector, description, timeout=60)[source]¶Waits for element specified by element_selector until it disappears from DOM.
Example usage:
self.wait_for_element_absence('.submit', 'Submit Button is not Present')
Parameters: |
|
---|
wait_for_element_invisibility
(element_selector, description, timeout=60)[source]¶Waits for element specified by element_selector until it disappears from the web page.
Example usage:
self.wait_for_element_invisibility('.submit', 'Submit Button Disappeared')
Parameters: |
|
---|
wait_for_element_presence
(element_selector, description, timeout=60)[source]¶Waits for element specified by element_selector to be present in DOM.
Example usage:
self.wait_for_element_presence('.submit', 'Submit Button is Present')
Parameters: |
|
---|
wait_for_element_visibility
(element_selector, description, timeout=60)[source]¶Waits for element specified by element_selector until it is displayed on web page.
Example usage:
self.wait_for_element_visibility('.submit', 'Submit Button is Visible')
Parameters: |
|
---|
wait_for_page
(timeout=30)[source]¶Block until the page loads, then returns the page. Useful for ensuring that we navigate successfully to a particular page.
Keyword Arguments: | |
---|---|
timeout (int) – The number of seconds to wait for the page before timing out with an exception. | |
Raises: | BrokenPromise – The timeout is exceeded without the page loading successfully. |
warning
(msg)[source]¶Subclasses call this to indicate that something unexpected occurred while interacting with the page.
Page objects themselves should never make assertions or raise exceptions, but they can issue warnings to make tests easier to debug.
Parameters: | msg (str) – The message to log as a warning. |
---|---|
Returns: | None |
bok_choy.page_object.
WrongPageError
[source]¶The page object reports that we’re on the wrong page!
bok_choy.page_object.
XSSExposureError
[source]¶An XSS issue has been found on the current page.
bok_choy.page_object.
no_selenium_errors
(func)[source]¶Decorator to create an EmptyPromise check function that is satisfied only when func executes without a Selenium error.
This protects against many common test failures due to timing issues. For example, accessing an element after it has been modified by JavaScript ordinarily results in a StaleElementException. Methods decorated with no_selenium_errors will simply retry if that happens, which makes tests more robust.
Parameters: | func (callable) – The function to execute, with retries if an error occurs. |
---|---|
Returns: | Decorated function |
Interface for running accessibility audits on a PageObject.
bok_choy.a11y.a11y_audit.
A11yAudit
(browser, url, config=None, *args, **kwargs)[source]¶Allows auditing of a page for accessibility issues.
The ruleset to use can be specified by the environment variable BOKCHOY_A11Y_RULESET. Currently, there are two ruleset implemented:
axe_core:
- Ruleset class: AxeCoreAudit
- Ruleset config: AxeCoreAuditConfig
- This is default ruleset.
google_axs:
- Ruleset class: AxsAudit
- Ruleset config: AxsAuditConfig
Sets ruleset to be used.
Parameters: |
|
---|
check_for_accessibility_errors
()[source]¶Run an accessibility audit, parse the results, and raise a single exception if there are violations.
Note that an exception is only raised on errors, not on warnings.
Returns: | None |
---|---|
Raises: | AccessibilityError |
default_config
¶Return an instance of a subclass of A11yAuditConfig.
bok_choy.a11y.a11y_audit.
A11yAuditConfig
(*args, **kwargs)[source]¶The A11yAuditConfig object defines the options available in an accessibility ruleset.
customize_ruleset
(custom_ruleset_file=None)[source]¶Allows customization of the ruleset. (e.g. adding custom rules, extending the implementation of an existing rule.)
Raises: | `NotImplementedError` if this isn’t overwritten in the ruleset – specific implementation. |
---|
set_rules
(rules)[source]¶Overrides the default rules to be run.
Raises: | `NotImplementedError` if this isn’t overwritten in the ruleset – specific implementation. |
---|
set_rules_file
(path=None)[source]¶Sets self.rules_file to the passed file.
Parameters: | filepath where the JavaScript for the ruleset can be found. (A) – |
---|
This is intended to be used in the case of using an extended or modified version of the ruleset. The interface and response format are expected to be unmodified.
Interface for using the google accessibility ruleset. See: https://github.com/GoogleChrome/accessibility-developer-tools
bok_choy.a11y.axs_ruleset.
AuditResults
(errors, warnings)¶Create new instance of AuditResults(errors, warnings)
errors
¶Alias for field number 0
warnings
¶Alias for field number 1
bok_choy.a11y.axs_ruleset.
AxsAudit
(browser, url, config=None, *args, **kwargs)[source]¶Use Google’s Accessibility Developer Tools to audit a page for accessibility problems.
See https://github.com/GoogleChrome/accessibility-developer-tools
Sets ruleset to be used.
Parameters: |
|
---|
default_config
¶Returns an instance of AxsAuditConfig.
bok_choy.a11y.axs_ruleset.
AxsAuditConfig
(*args, **kwargs)[source]¶The AxsAuditConfig object defines the options available when running an AxsAudit.
customize_ruleset
(custom_ruleset_file=None)[source]¶This has not been implemented for the google_axs ruleset.
Raises: | NotImplementedError |
---|
set_rules
(rules)[source]¶Sets the rules to be run or ignored for the audit.
Parameters: | rules – a dictionary of the format {“ignore”: [], “apply”: []}. |
---|
See https://github.com/GoogleChrome/accessibility-developer-tools/tree/master/src/audits
Passing {“apply”: []} or {} means to check for all available rules.
Passing {“apply”: None} means that no audit should be done for this page.
Passing {“ignore”: []} means to run all otherwise enabled rules. Any rules in the “ignore” list will be ignored even if they were also specified in the “apply”.
Examples
To check only badAriaAttributeValue:
page.a11y_audit.config.set_rules({
"apply": ['badAriaAttributeValue']
})
To check all rules except badAriaAttributeValue:
page.a11y_audit.config.set_rules({
"ignore": ['badAriaAttributeValue'],
})
set_scope
(include=None, exclude=None)[source]¶Sets scope, the “start point” for the audit.
Parameters: |
|
---|
Examples
To check only the div with id foo:
page.a11y_audit.config.set_scope(["div#foo"])
To reset the scope to check the whole document:
page.a11y_audit.config.set_scope()
Interface for using the axe-core ruleset. See: https://github.com/dequelabs/axe-core
bok_choy.a11y.axe_core_ruleset.
AxeCoreAudit
(browser, url, config=None, *args, **kwargs)[source]¶Use Deque Labs’ axe-core engine to audit a page for accessibility issues.
Related documentation:
Sets ruleset to be used.
Parameters: |
|
---|
default_config
¶Returns an instance of AxeCoreAuditConfig.
format_errors
(errors)[source]¶Parameters: | errors – results of AxeCoreAudit.get_errors(). |
---|
Returns: The errors as a formatted string.
bok_choy.a11y.axe_core_ruleset.
AxeCoreAuditConfig
(*args, **kwargs)[source]¶The AxeCoreAuditConfig object defines the options available when running an AxeCoreAudit.
customize_ruleset
(custom_ruleset_file=None)[source]¶Updates the ruleset to include a set of custom rules. These rules will be _added_ to the existing ruleset or replace the existing rule with the same ID.
Parameters: | custom_ruleset_file (optional) – The filepath to the custom rules. Defaults to None. If custom_ruleset_file isn’t passed, the environment variable BOKCHOY_A11Y_CUSTOM_RULES_FILE will be checked. If a filepath isn’t specified by either of these methods, the ruleset will not be updated. |
---|---|
Raises: | IOError if the specified file does not exist. |
Examples
To include the rules defined in axe-core-custom-rules.js:
page.a11y_audit.config.customize_ruleset(
"axe-core-custom-rules.js"
)
Alternatively, use the environment variable BOKCHOY_A11Y_CUSTOM_RULES_FILE to specify the path to the file containing the custom rules.
Documentation for how to write rules:
An example of a custom rules file can be found at https://github.com/edx/bok-choy/tree/master/tests/a11y_custom_rules.js
set_rules
(rules)[source]¶Set rules to ignore XOR limit to when checking for accessibility errors on the page.
Parameters: | rules – a dictionary one of the following formats. If you want to run all of the rules except for some: {"ignore": []}
If you want to run only a specific set of rules: {"apply": []}
If you want to run only rules of a specific standard: {"tags": []}
|
---|
Examples
To run only “bad-link” and “color-contrast” rules:
page.a11y_audit.config.set_rules({
"apply": ["bad-link", "color-contrast"],
})
To run all rules except for “bad-link” and “color-contrast”:
page.a11y_audit.config.set_rules({
"ignore": ["bad-link", "color-contrast"],
})
To run only WCAG 2.0 Level A rules:
page.a11y_audit.config.set_rules({
"tags": ["wcag2a"],
})
Related documentation:
set_scope
(include=None, exclude=None)[source]¶Sets scope (refered to as context in ruleset documentation), which defines the elements on a page to include or exclude in the audit. If neither include nor exclude are passed, the entire document will be included.
Parameters: |
|
---|
Examples
To include all items in #main-content except #some-special-elm:
page.a11y_audit.config.set_scope(
exclude=["#some-special-elm"],
include=["#main-content"]
)
To include all items in the document except #some-special-elm:
page.a11y_audit.config.set_scope(
exclude=["#some-special-elm"],
)
To include only children of #some-special-elm:
page.a11y_audit.config.set_scope(
include=["#some-special-elm"],
)
Context documentation:
https://github.com/dequelabs/axe-core/blob/master/doc/API.md#a-context-parameter
Note that this implementation only supports css selectors. It does not accept nodes as described in the above documentation resource.
Variation on the “promise” design pattern. Promises make it easier to handle asynchronous operations correctly.
bok_choy.promise.
BrokenPromise
(promise)[source]¶The promise was not satisfied within the time constraints.
Configure the broken promise error.
Parameters: | promise (Promise) – The promise that was not satisfied. |
---|
bok_choy.promise.
EmptyPromise
(check_func, description, **kwargs)[source]¶A promise that has no result value.
Configure the promise.
Unlike a regular Promise, the check_func() does NOT return a tuple with a result value. That’s why the promise is “empty” – you don’t get anything back.
Example usage:
# This will block until `is_done` returns `True` or we reach the timeout limit.
EmptyPromise(lambda: is_done('test'), "Test operation is done").fulfill()
Parameters: |
|
---|---|
Returns: | EmptyPromise |
bok_choy.promise.
Promise
(check_func, description, try_limit=None, try_interval=0.5, timeout=30)[source]¶Check that an asynchronous action completed, blocking until it does or timeout / try limits are reached.
Configure the Promise.
If the try_limit or timeout is reached without success, then the promise is “broken” and an exception will be raised.
Note that if you specify a try_limit but not a timeout, the default timeout is still used. This is to prevent an inadvertent infinite loop. If you want to make sure that the try_limit expires first (and thus that many attempts will be made), then you should also pass in a larger value for timeout.
description is a string that will be included in the exception to make debugging easier.
Example:
# Dummy check function that indicates the promise is always satisfied
check_func = lambda: (True, "Hello world!")
# Check up to 5 times if the operation has completed
result = Promise(check_func, "Operation has completed", try_limit=5).fulfill()
Parameters: |
|
---|---|
Keyword Arguments: | |
|
|
Returns: | Promise |
fulfill
()[source]¶Evaluate the promise and return the result.
Returns: | The result of the Promise (second return value from the check_func) |
---|---|
Raises: | BrokenPromise – the Promise was not satisfied within the time or attempt limits. |
Tools for interacting with the DOM inside a browser.
bok_choy.query.
BrowserQuery
(browser, **kwargs)[source]¶A Query that operates on a browser.
Generate a query over a browser.
Parameters: | browser (selenium.webdriver) – A Selenium-controlled browser. |
---|---|
Keyword Arguments: | |
|
|
Returns: | BrowserQuery |
Raises: |
|
attrs
(attribute_name)[source]¶Retrieve HTML attribute values from the elements matched by the query.
Example usage:
# Assume that the query matches html elements:
# <div class="foo"> and <div class="bar">
>> q.attrs('class')
['foo', 'bar']
Parameters: | attribute_name (str) – The name of the attribute values to retrieve. |
---|---|
Returns: | A list of attribute values for attribute_name. |
click
()[source]¶Click each matched element.
Example usage:
# Click the first element matched by the query
q.first.click()
Returns: | None |
---|
fill
(text)[source]¶Set the text value of each matched element to text.
Example usage:
# Set the text of the first element matched by the query to "Foo"
q.first.fill('Foo')
Parameters: | text (str) – The text used to fill the element (usually a text field or text area). |
---|---|
Returns: | None |
focused
¶Checks that at least one matched element is focused. More specifically, it checks whether the element is document.activeElement. If no matching element is focused, this returns False.
Returns: | bool |
---|
html
¶Retrieve the inner HTML of each element matched by the query.
Example usage:
# Assume that the query matches html elements:
# <div><span>Foo</span></div> and <div>Bar</div>
>> q.html
['<span>Foo</span>', 'Bar']
Returns: | The inner HTML for each element matched by the query. |
---|
invisible
¶Check whether all matched elements are present, but not visible.
Returns: | bool |
---|
is_focused
()[source]¶Checks that at least one matched element is focused. More specifically, it checks whether the element is document.activeElement. If no matching element is focused, this returns False.
Returns: | bool |
---|
selected
¶Check whether all the matched elements are selected.
Returns: | bool |
---|
text
¶Retrieve text from each matched element.
Example usage:
# Assume that the query matches html elements:
# <div>Foo</div> and <div>Bar</div>
>> q.text
['Foo', 'Bar']
Returns: | The text of each element matched by the query. |
---|
visible
¶Check whether all matched elements are visible.
Returns: | bool |
---|
bok_choy.query.
Query
(seed_fn, desc=None)[source]¶General mechanism for selecting and transforming values.
Configure the Query.
Parameters: | seed_fn (callable) – Callable with no arguments that produces a list of values. |
---|---|
Keyword Arguments: | |
desc (str) – A description of the query, used in log messages. If not provided, defaults to the name of the seed function. | |
Returns: | Query |
execute
(try_limit=5, try_interval=0.5, timeout=30)[source]¶Execute this query, retrying based on the supplied parameters.
Keyword Arguments: | |
---|---|
|
|
Returns: | The transformed results of the query. |
Raises: |
|
filter
(filter_fn=None, desc=None, **kwargs)[source]¶Return a copy of this query, with some values removed.
Example usages:
# Returns a query that matches even numbers
q.filter(filter_fn=lambda x: x % 2)
# Returns a query that matches elements with el.description == "foo"
q.filter(description="foo")
Keyword Arguments: | |
---|---|
|
|
Raises: |
|
first
¶Return a Query that selects only the first element of this Query. If no elements are available, returns a query with no results.
Example usage:
>> q = Query(lambda: list(range(5)))
>> q.first.results
[0]
Returns: | Query |
---|
is_present
()[source]¶Check whether the query returns any results.
Returns: | Boolean indicating whether the query contains any results. |
---|
map
(map_fn, desc=None)[source]¶Return a copy of this query, with the values mapped through map_fn.
Parameters: | map_fn (callable) – A callable that takes a single argument and returns a new value. |
---|---|
Keyword Arguments: | |
desc (str) – A description of the mapping transform, for use in log message. Defaults to the name of the map function. | |
Returns: | Query |
nth
(index)[source]¶Return a query that selects the element at index (starts from 0). If no elements are available, returns a query with no results.
Example usage:
>> q = Query(lambda: list(range(5)))
>> q.nth(2).results
[2]
Parameters: | index (int) – The index of the element to select (starts from 0) |
---|---|
Returns: | Query |
present
¶Check whether the query returns any results.
Returns: | Boolean indicating whether the query contains any results. |
---|
replace
(**kwargs)[source]¶Return a copy of this Query, but with attributes specified as keyword arguments replaced by the keyword values.
Keyword Arguments: | |
---|---|
to replace in the copy. (Attributes/values) – | |
Returns: | A copy of the query that has its attributes updated with the specified values. |
Raises: | TypeError – The Query does not have the specified attribute. |
results
¶A list of the results of the query, which are cached. If you call results multiple times on the same query, you will always get the same results. Use reset() to clear the cache and re-run the query.
Returns: | The results from executing the query. |
---|
transform
(transform, desc=None)[source]¶Create a copy of this query, transformed by transform.
Parameters: | transform (callable) – Callable that takes an iterable of values and returns an iterable of transformed values. |
---|---|
Keyword Arguments: | |
desc (str) – A description of the transform, to use in log messages. Defaults to the name of the transform function. | |
Returns: | Query |
bok_choy.query.
no_error
(func)[source]¶Decorator to create a Promise check function that is satisfied only when func executes without a Selenium error.
This protects against many common test failures due to timing issues. For example, accessing an element after it has been modified by JavaScript ordinarily results in a StaleElementException. Methods decorated with no_error will simply retry if that happens, which makes tests more robust.
Parameters: | func (callable) – The function to execute, with retries if an error occurs. |
---|---|
Returns: | Decorated function |
Base class for testing a web application.
bok_choy.web_app_test.
WebAppTest
(*args, **kwargs)[source]¶Base class for testing a web application.
get_web_driver
()[source]¶Override NeedleTestCases’s get_web_driver class method to return the WebDriver instance that is already being used, instead of starting up a new one.
setUp
()[source]¶Start the browser for use by the test. You must call this in the setUp method of any subclasses before using the browser!
Returns: | None |
---|
setUpClass
()[source]¶Override NeedleTestCase’s setUpClass method so that it does not start up the browser once for each testcase class. Instead we start up the browser once per TestCase instance, in the setUp method.
set_viewport_size
(width, height)[source]¶Override NeedleTestCases’s set_viewport_size class method because we need it to operate on the instance not the class.
See the Needle documentation at http://needle.readthedocs.org/ for information on this feature. It is particularly useful to predict the size of the resulting screenshots when taking fullscreen captures, or to test responsive sites.
tearDownClass
()[source]¶Override NeedleTestCase’s tearDownClass method because it would quit the browser. This is not needed as we have already quit the browser after each TestCase, by virtue of a cleanup that we add in the setUp method.
unique_id
¶Helper method to return a uuid.
Returns: | 39-char UUID string |
---|