Base class
The base class contains generic and reusable methods and these methods are nothing but wrappers developed on top of selenium webdriver classes and methods.
The following code depicts a base class having few generic, static and reusable methods defined. 
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.wait import WebDriverWait
from selenium.common.exceptions import *
import utilities.logger as cl
import inspect
from traceback import print_stack
import time
from datetime import datetime
import os
from selenium.webdriver.support.ui import Select
from selenium.webdriver import ActionChains
import logging


# This is a base class
class SeleniumDriver(): """
 This is a base class containing all the generic/reusable and static methods
 """

 # Object of logger class
    log_base = cl.customlogger(loglevel=logging.DEBUG)

    # Constructor to initialize driver    def __init__(self, driver):
        self.driver = driver

    def get_by_type(self, locatorType): """
 This method will return the by type for the locatorType argument.
 =================================================================
 Parameter:
 ----------
 1. Required:
   1. locatorType: [id, name, class, link-text, xpath, css, tag etc.]
 Return:
 -------
   It returns By locator types e.g. By.ID, By.NAME etc.
 Exception:
 ----------
   Error if locatorType is not correct/supported
 """
        log_base = cl.customlogger(loglevel=logging.DEBUG)
        locatorType = locatorType.lower()
        if locatorType == 'id':
            return By.ID
        if locatorType == 'name':
            return By.NAME
        if locatorType == 'class':
            return By.CLASS_NAME
        if locatorType == 'link-text':
            return By.LINK_TEXT
        if locatorType == 'xpath':
            return By.XPATH
        if locatorType == 'css':
            return By.CSS_SELECTOR
        if locatorType == 'tag':
            return By.TAG_NAME
        else:
            self.log_base.info("[FAIL] Test method '{0}-->{1}".format(__name__,
                           inspect.currentframe().f_code.co_name) + "Locator type " + locatorType +
                          " not correct/supported")
        return False
    def get_element(self, locator, locatorType="id"):
 """
 This method will find out an element according to the combination of locator and locatorType.
 =============================================================================================
 Parameter:----------
 1. Required
   1. locator
   2. locatorType
 Return:
 -------
   Element
 Exception:
 ----------
   NoSuchElementException
 """
        element = None        try:
            locatorType = locatorType.lower()
            byType = self.get_by_type(locatorType)
            element = self.driver.find_element(byType, locator)
            self.log_base.info("[PASS] Test method: '{0}-->{1}'".format(__name__,
                      inspect.currentframe().f_code.co_name) + "Element found with locator: " +
                       locator + " and  locatorType: " + locatorType)
        except:
            self.log_base.error("[ERROR] Test method: '{0}{1}'".format(__name__,
             inspect.currentframe().f_code.co_name) + "Element not found with locator: " + 
            locator + " and locatorType: " + locatorType +" ###Exception: {}".format(NoSuchElementException))
        return element

    def get_element_list(self, locator, locatorType="id"):

 """
 This method is useful for fetching multiple elements from parent element
 ========================================================================
 Parameter:
 ----------
 1. Required:
   1. locator
   2. locatorType
 Return:
 -------
   It returns list of elements
 Exception:
 ----------
   Element list NOT FOUND error
 """        locatorType = locatorType.lower()
        byType = self.get_by_type(locatorType)
        elements = self.driver.find_elements(byType, locator)
        if len(elements) > 0:
            self.log_base.info("[PASS] Test method: '{0}-->{1}'".format(__name__,
                         inspect.currentframe().f_code.co_name) + "Element list FOUND with locator: " +
                         locator + " and locatorType: " + locatorType)
        else:
            self.log_base.info("[FAIL] Test method: '{0}-->{1}'".format(__name__,
                          inspect.currentframe().f_code.co_name) + "Element list NOT FOUND with locator: " +
                          locator + " and locatorType: " + locatorType)
        return elements

    def get_element_type(self, locator, locatorType): """
 This method will return type of an element.
 ===========================================
 Parameter:
 ----------
 1. Required
   1. locator
   2. locatorType
 Return:
 -------
   It returns element_type.
 Exception:
 ----------
   None
 """
        element = self.get_element(locator, locatorType)
        element_type = element.get_attribute("type")
        if element_type == 'text':
            return element_type
        if element_type == 'radio':
            return element_type
        if element_type == 'checkbox':
            return element_type
        if element_type == 'submit':
            return element_type

    def driver_close(self):
      """
    Driver instance will be closed
    :return: It doesn't return anything
    """
        self.driver.close()
        self.log_base.info("[PASS] Driver is successfully closed using test method:"'{0}-->{1}'".
                   format(__name__, inspect.currentframe().f_code.co_name))

    def sendKeys(self, data, locator, locatorType="id", element=None): """
 Send keys to an element -> MODIFIED
 Either provide element or a combination of locator and locatorType
 """
        try:
            if locator:  # This means if locator is not empty
                element = self.get_element(locator, locatorType)
            element.send_keys(data)
            self.log_base.info("[PASS] Sent data '{0}' on element with locator: ".format(data)
                          + locator + " locatorType: " + locatorType +
                          "using test method '{0}-->{1}'" format(__name__, inspect.currentframe().f_code.co_name))
        except:
            self.log_base.error("[FAIL] Cannot send data '{0}' on the element with locator: "
           .format(data) + locator + " locatorType: " + locatorType + "using test method ""'{0}-->{1}'"
          .format(__name__, inspect.currentframe().f_code.co_name))
            print_stack()

    def element_click(self, locator, locatorType="id", element=None):    """
    Click on an element -> MODIFIED
    Either provide element or a combination of locator and locatorType
    """
        try:
            if locator:  # This means if locator is not empty
                element = self.get_element(locator, locatorType)
            element.click()
            self.log_base.info("[PASS] Clicked on element with locator: " + locator +
               " locatorType: " + locatorType + "using test method '{0}-->{1}'".format(__name__,
                inspect.currentframe().f_code.co_name))
        except:
            self.log_base.error("[FAIL] Cannot click on the element with locator: " + locator +
                  " locatorType: " + locatorType + "using test method '{0}-->{1}'".format(__name__,
                   inspect.currentframe().f_code.co_name))
            print_stack()

    def capture_screenshot(self, resultMessage):   """
   Takes screenshot of the current open web page
   """
        now = datetime.now()
        fileName = resultMessage + "." + \
            str(now.strftime("%Y%m%d%H:%M:%S %p")) + ".png"

        screenshotDirectory = "/Users/pravin.a/my-project/venv/MyFramework/screenshots/{0}{1}{2}".
             format("screenshots", "_", str(now.strftime("%Y%m%d")))
        relativeFileName = fileName
        currentDirectory = os.path.dirname(__file__)
        destinationFile = os.path.join(screenshotDirectory, relativeFileName)
        destinationDirectory = os.path.join(
            currentDirectory, screenshotDirectory)

        try:
            if not os.path.exists(destinationDirectory):
                os.makedirs(destinationDirectory)
            self.driver.save_screenshot(destinationFile)
            self.log_base.info("[PASS] Test method: '{0}-->{1}'".format(__name__,
                inspect.currentframe().f_code.co_name) + ":" + " Screenshot save to directory:"+ destinationFile)
        except:
            self.log_base.error("[FAIL] Test method: '{0}-->{1}'".format(__name__,
                  inspect.currentframe().f_code.co_name) + "### Exception Occurred when taking screenshot")
            print_stack()

    def get_title(self):
       """
     This method returns title of the current page.
     """
        return self.driver.title

    def clear_field(self, locator, locatorType="id"):
        """
     This method will Clear an element field.
     """
        element = self.get_element(locator, locatorType)
        element.clear()
        self.log_base.info("[PASS] Test method: '{0}-->{1}'".format(__name__,
                 inspect.currentframe().f_code.co_name) + "Clear field with locator: " +locator + 
                " locatorType: " + locatorType)

    def get_text(self, locator, locatorType="id", element=None, info=""):
    """
   NEW METHOD
   Get 'Text' on an element
    Either provide element or a combination of locator and locatorType        """        try:
            if locator:  # This means if locator is not empty
                element = self.get_element(locator, locatorType)
            text = element.text
            if len(text) == 0:
                text = element.get_attribute("innerText")
            if len(text) != 0:
                self.log_base.info("[PASS] Test method: '{0}{1}'".format(
                    __name__, inspect.currentframe().f_code.co_name) + "Getting text on element ::"+ info)
                self.log_base.info("The text is :: '" + text + "'")
                text = text.strip()
        except:
            self.log_base.error("[FAIL] Test method: '{0}{1}'".format(
               __name__, inspect.currentframe().f_code.co_name) + "Failed to get text on element"+ info)
            print_stack()
            text = None        return text

    def is_element_present(self, locator, locatorType="id", element=None):   """
   Check if element is present -> MODIFIED
   Either provide element or a combination of locator and locatorType
        """
        try:
            if locator:  # This means if locator is not empty
                element = self.get_element(locator, locatorType)
            if element is not None:
                self.log_base.info("[PASS] Test Method: '{0}-->{1}'".format(__name__,
                    inspect.currentframe().f_code.co_name) + "Element present with locator: "+ locator +
                    " locatorType: " + locatorType)
                return True            else:
                self.log_base.error("[FAIL] Test method: '{0}-->{1}'".format(__name__,
                     inspect.currentframe().f_code.co_name) + "Element not present with locator: "+ locator + 
                   " locatorType: " + locatorType)
                return False        except:
            print("[FAIL] Test method: '{0}-->{1}'".format(__name__, inspect.currentframe()
                 .f_code.co_name) + "Element not found" + "###Exception-->{}".format
                 (NoSuchElementException))
            return False
    def is_element_displayed(self, locator, locatorType="id", element=None):   """
   NEW METHOD
   Check if element is displayed
   Either provide element or a combination of locator and locatorType
   """
        isDisplayed = False        try:
            if locator:  # This means if locator is not empty
                element = self.get_element(locator, locatorType)
            if element is not None:
                isDisplayed = element.isDisplayed()
                self.log_base.info("[PASS] Test method: '{0}-->{1}'".format(
                    __name__, inspect.currentframe().f_code.co_name) + "Element is displayed")
            else:
                self.log_base.info("[FAIL] Test method: '{0}-->{1}'".format(
                    __name__, inspect.currentframe().f_code.co_name) + "Element is not displayed")
            return isDisplayed
        except:
            print("[ERROR] Test method: '{0}-->{1}'".format(__name__,
                     inspect.currentframe().f_code.co_name) + "Element not found" +
                  "###Exception-->{}".format(ElementNotVisibleException))
            return False
    def wait_for_element(self, locator, locatorType="id",
                         timeout=10, pollFrequency=0.5):   """
   This method will make webdriver to wait for a particular amount of time.
   """
        element = None        try:
            byType = self.get_by_type(locatorType)
            self.log_base.info("Waiting for maximum :: " + str(timeout) +
                          " :: seconds for element to be clickable")
            wait = WebDriverWait(self.driver, timeout=timeout,
                                 poll_frequency=pollFrequency,
                                 ignored_exceptions=[NoSuchElementException,
                                                     ElementNotVisibleException,
                                                     ElementNotSelectableException])
            element = wait.until(EC.element_to_be_clickable((byType, locator)))
            self.log_base.info("[PASS] Test method '{0}-->{1}'".format(__name__,
                      inspect.currentframe().f_code.co_name) + "Element appeared on the web page" +
                      "with locator" + locator + "and locatortype" + locatorType)
        except:
            self.log_base.info("[FAIL] Test method '{0}-->{1}'".format(__name__,
                  inspect.currentframe().f_code.co_name) + "Element not appeared on the web page"
                  + "with locator" + locator + "and locatortype" + locatorType)
            print_stack()
        return element

    def element_presence_check(self, locator, byType):   """
   Check if element is present
   =============================
   Parameter:
   ----------
   Required:
     1. locator
     2. byType
   Return:
   -------
     If element present --> Returns True
     If element absent --> Returns False
   Exception:
   ----------
     NoSuchElementException
   """
        try:
            elementList = self.driver.find_elements(byType, locator)
            if len(elementList) > 0:
                self.log_base.info("[PASS] Test method '{0}-->{1}'".format(__name__,
                      inspect.currentframe().f_code.co_name) + "Element present with locator: "+ locator + 
                      " locatorType: " + str(byType))
                return True            else:
                self.log_base.info("[FAIL] Test method '{0}-->{1}'".format(__name__,
                     inspect.currentframe().f_code.co_name) + "Element not present with locator: "+ locator + 
                    " locatorType: " + str(byType))
                return False        except:
            self.log_base.info("[ERROR] Test method: '{0}-->{1}'".format(__name__,
                    inspect.currentframe().f_code.co_name) + "Element not found," +"###Exception-->{}".
                    format(NoSuchElementException))
            return False
    def web_scroll(self, direction="up"):   """
   NEW METHOD
   """
        if direction == "up":
            # Scroll Up            self.driver.execute_script("window.scrollBy(0, -800);")

        if direction == "down":
            # Scroll Down            self.driver.execute_script("window.scrollBy(0, 600);")

    def switch_to_frame(self, id="", name="", index=None): """
 Switch to iframe using element locator inside iframe

 Parameters:
 1. Required:
    Either id, name or index
 Returns:
   None
 Exception:
   None        """
        if id:
            self.driver.switch_to.frame(id)
            self.log_base.info("Test Method: '{0}{1}'".format(__class__, inspect.currentframe(
            ).f_code.co_name) + "Controll is switched to frame with id:  '{}'".format(id))
        elif name:
            self.driver.switch_to.frame(name)
            self.log_base.info("Test Method: '{0}{1}'".format(__class__, inspect.currentframe(
            ).f_code.co_name) + "Controll is switched to frame with name:  '{}'".format(name))
        else:
            self.driver.switch_to.frame(index)
            self.log_base.info("Test Method: '{0}{1}'".format(__class__, inspect.currentframe(
            ).f_code.co_name) + "Controll is switched to frame with index '{}'".format(index))

    def switch_to_window(self):
        parent_handle = self.driver.current_window_handle
        all_handles = self.driver.window_handles
        try:
            for handle in all_handles:
                if handle not in parent_handle:
                    self.driver.switch_to.window(handle)
                    self.log_base.info("Test Method: '{0}{1}'".format(__class__, inspect.currentframe(
                          ).f_code.co_name) + "switched to a new window '{}'".format(handle))
        except:
            self.log_base.error("Test Method: '{0}{1}'".format(__class__, inspect.currentframe(
                ).f_code.co_name) + "Invalid window handle, control can't be switched to the "handle:")
        return parent_handle


    def switch_to_default_content(self, parent_handle): """
 Switch to default content
 Parameters:
 1. Required:
     1. parent_handle
 Returns:
    None
 Exception:
    None
 """
        self.driver.switch_to.window(parent_handle)
        #self.driver.switch_to_default_content()

        self.log_base.info("Test Method '{}{}'".format(__class__, inspect.currentframe(
        ).f_code.co_name) + "Control is switched back to default content")

    def alert_popups(self, choice):
        alert_popup = self.driver.switch_to.alert
        if choice in ['ok', 'Ok', 'OK']:
            alert_popup.accept()
        elif choice in ['cancel', 'Cancel', 'CANCEL']:
            alert_popup.dismiss()
        else:
            self.log_base.error("Test Method '{}{}'".format(__class__, inspect.currentframe(
        ).f_code.co_name) + " " + "Invalid choice")


    def get_element_attribute_value(self, attribute, locator="", locatorType="", element=None):

 """
 Get value of the attribute of element
 Parameters:
 1. Required:
     1. attribute - attribute whose value to find
 2. Optional:
    1. element - Element whose attribute need to find
    2. locator - Locator of the element
    3. locatorType - Locator Type to find the element
 Returns:
 Value of the attribute
 Exception:
 None
 """
        if locator:
            element = self.get_element(
                locator=locator, locatorType=locatorType)
        value = element.get_attribute(attribute)
        if value is not None:
            self.log_base.info("Test Method '{0}{1}'".format(__class__, inspect.currentframe(
            ).f_code.co_name) + "Attribute value is: {} ".format(value))
        else:
            self.log_base.warn("Test Method '{0}{1}'".format(__class__, inspect.currentframe(
            ).f_code.co_name) + "Attribute value is not returned" + "Make sure an element you 
             are looking for is a valid element")
        return value

    def is_enabled(self, locator, locatortype="id", info=""): """
 Check if element is enabled

 Parameters:
 1. Required:
    1. locator - Locator of the element to check
 2. Optional:
    1. locatorType - Type of the locator(id(default), xpath, css, className, linkText)
    2. info - Information about the element, label/name of the element
 Returns:
 boolean
 Exception:
 None
 """
        element = self.get_element(locator, locatorType=locatortype)
        enabled = False        try:
            attributeValue = self.get_element_attribute_value(
                element=element, attribute="disabled")
            if attributeValue is not None:
                enabled = element.is_enabled()
            else:
                value = self.get_element_attribute_value(
                    element=element, attribute="class")
                self.log_base.info(
                    "Attribute value From Application Web UI --> :: " + value)
                enabled = not ("disabled" in value)
            if enabled:
                self.log_base.info("Element :: '" + info + "' is enabled")
            else:
                self.log_base.info("Element :: '" + info + "' is not enabled")
        except:
            self.log_base.error("Element :: '" + info +
                           "' state could not be found")
        return enabled

    def select_option(self, locator, locatorType="id", index=None, text=None,
                      value=None, element=None): """
 This method will select an required option/item/element from select element.
 Parameters:
 1. Required:
   1. locator
   2. locatorType
   3. Either index Or text Or value
 2. Optional:
   1. element
 Returns:
 It doesn't return anything
 Exception:
 None
 """
        if locator:
            element = self.get_element(locator, locatorType=locatorType)
        select = Select(element)
        if index is not None:
            select.select_by_index(index)
            self.log_base.info('Test Method:"{0}{1}"'.format(__class__, inspect.currentframe
                          ().f_code.co_name) + "is successful. " + "Element is selected successfully")
        elif text is not None:
            select.select_by_visible_text(text)
            self.log_base.info('Test Method:"{0}{1}"'.format(__class__, inspect.currentframe
                   ().f_code.co_name) + "is successful. " + "Element '{}' is selected successfully".format(text))
        elif value is not None:
            select.select_by_value(value)
            self.log_base.info('Test Method:"{0}{1}"'.format(__class__, inspect.currentframe
                                          ().f_code.co_name) + "is successful. " + "Element '{}' is selected successfully".
                               format(value))
        else:
            print("Invalid argument to select method")
            self.log_base.error("Test method: '{0}{1}'".format(__class__, inspect.currentframe
                                 ().f_code.co_name) + "is failed. " + "Unable to select an item" + "'{}'".
                                format('"Invalid argument to select method"'))

    def deselect_all(self, locator, locatorType): """
 This method will deselect all the selected items/options from the select element.
 Parameter:
 1. Required:
   1. locator
   2 locatorType
 2. Optional:
   None
 Return:
 element [*Note - This is optional]
 Exception:
 None
 """
        element = self.get_element(locator, locatorType=locatorType)
        select = Select(element)
        select.deselect_all()
        self.log_base.info("Test Method '{0}{1}'".format(
          __class__, inspect.currentframe().f_code.co_name) + "Elements are deselected")
        return element

    def get_all_selected_options(self, locator, locatorType):
        element = self.get_element(locator, locatorType=locatorType)
        select = Select(element)
        allSelectedOptions = select.all_selected_options
        return allSelectedOptions, element

    def get_all_options(self, locator="", locatorType="id", element=None): """
 This method will find out and return all the options from Select element.
 Parameter:
 1. Required:
   1. locator
   2 locatorType
 2. Optional:
   1. element
 Return:
 None
 Exception:
 None
 """
        if locator:
            element = self.get_element(locator, locatorType=locatorType)
            select = Select(element)
            options = select.options
            return options
        if element:
            select = Select(element)
            options = select.options
            return options

    def drag_and_drop(self, source, target): """
 This method will drag the source element to a target/destination element.
 Parameter:
 1. Required:
   1. source - source from which files are required to be copied.
   2. target - target at which files needs to be copied.
 2. Optional:
  None
 Return:
  None
 Exception:
  None
 """
        action_chains = ActionChains(self.driver)
        # Disable below line of code if doesn't work.
        action_chains.drag_and_drop(source, target).perform()

        # Enable below line of code if above code doesn't work.
        action_chains.click_and_hold(source).release(target).perform()

    def file_upload(self, locator, locatorType, file_path, element=None): """
 This method will upload the required file at the desired location.
 Parameter:
 1. Required:
   1. locator
   2. locatorType
   3. file_path
 2. Optional:
   1. element
 Return:
   None
 Exception:
   None
 """
        if locator:
            element = self.get_element(
                locator=locator, locatorType=locatorType)
            element.send_keys(file_path)
        else:
            self.sendKeys(data=file_path, element=element, locator="")

    def get_data_web_table(self, locator, locatorType="id", element=None):
  """
 :param locator: locator to find out an element
 :param locatorType: default locator type is 'id'
 :param element: By default element is set to None and it will be set to the value as passed through the script.
 :return: It returns a list of cell values from the web table
 """
        web_table_list = []
        if locator:
            table = self.get_element(locator, locatorType)
            element = table
        for row in element.find_elements(By.XPATH, ".//tr"):
            for cell in row.find_elements(By.XPATH, './/td'):
                web_table_list.append(cell.text)
        return web_table_list


=================================================================================
Similarly, you can create generic methods for your UI to be tested under this base class.

Comments

Popular Posts

Image