Source code for selenium_docker.helpers

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# >>
#   Copyright 2018 Vivint, inc.
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
#
#    vivint-selenium-docker, 20017
# <<

import logging

from aenum import Flag
from toolz.functoolz import memoize
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as expect, ui

from selenium_docker.errors import SeleniumError

HTML_TAG = (By.TAG_NAME, 'html')
"""(str, str): tuple representing an <HTML> tag."""


[docs]class JsonFlags(Flag): """ :obj:`aenum.Flag` mixin to return members as JSON dict. """
[docs] @classmethod def as_json(cls): """ Converts the Flag enumeration to a JSON structure. Returns: dict(str, int): Flag names and their corresponding integer-bit-value. """ return {str(k): v.value for k, v in cls.__members__.items()}
[docs] @classmethod def from_values(cls, *values): """ Creates a compound Flag instance. Logically OR's the integer/string ``values`` and returns a bit-flag that represents the features we want enabled in our Driver instance. Args: values (int or str): the integer-bit value or the flag name. Returns: :obj:`aenum.Flag`: Compound Flag instance with the features we requested. """ ret = cls(0) for v in values: if isinstance(v, str): x = cls.__members__.get(v) elif isinstance(v, int): x = cls(v) elif v is None: continue else: raise ValueError(v) ret = ret | x return ret
[docs]class OperationsMixin(object): """ Optional mixin object to extend default driver functionality. """ @property @memoize(key=lambda self: id(self)) def _log(self): log = getattr(self, 'logger', None) if log and hasattr(log, 'exception'): return log else: logger = logging.getLogger('_blank') logger.addHandler(logging.NullHandler()) return logger
[docs] def switch_to_frame(self, selector, wait_for=HTML_TAG, max_time=30): """ Wait for a frame to load then switch to it. Note: Because there are two waits being performed in this operation the ``max_wait`` time could be doubled at most the value applied. Args: selector (tuple): ``iFrame`` we're looking for, in the form of ``(By, str)``. wait_for (tuple): element to wait for inside the iFrame, in the form of ``(By, str)``. max_time (int): time in seconds to wait for each element. Raises: Exception; when anything goes wrong. Returns: :obj:`~selenium.webdriver.remote.webelement.WebElement`: when there were no exceptions and the operation completed successfully. """ wait = ui.WebDriverWait(self, max_time, poll_frequency=0.25) try: wait.until(expect.frame_to_be_available_and_switch_to_it(selector)) wait.until(expect.visibility_of(wait_for)) el = self.find_element(*wait_for) except SeleniumError as e: self._log.exception(e, exc_info=True) raise e return el