Search code examples
pythonjsonseleniumpyyaml

Data driven tests. reading parameters from a .json or .yaml file using Selenium Python


I create a framework using Selenium and Python. My data driven framework consists of 2 files so far: The 1st file- Setup.py contains class Actions() that consist of all possible functions that I will use in my framework, such as:

def __init__(): 
def setup():
def tearDown():
def click():
def sendKeys():

My click and sendKeys functions have a minimum of 2 parameters. They take the first parameter such us :id_for_element, xp_for_element, or css_for_element, slicing words until they get the 1st two characters and find element by either id, xp or any other way. Then they use the 2nd parameter to specify an element's value, and 3rd parameter to specify a value for send_keys() function. All of these functions are now working, but so far value hardcoded in my test file.

setup.py file:

from   selenium import webdriver
from   selenium.webdriver.common.by import By
from   selenium.webdriver.common.keys import Keys
from   selenium.webdriver.support.ui import Select
from   selenium.common.exceptions import NoSuchElementException
from   selenium.common.exceptions import NoAlertPresentException

class Actions(object):

    def __init__(self,driver=None):
        if driver != None:
            self.driver = driver

    def setUp(self, browserName):
        if browserName == 'Chrome':
            self.driver = webdriver.Chrome()
            self.driver.delete_all_cookies()
            self.driver.maximize_window()
        elif browserName == 'Safari':
            self.driver = webdriver.Safari()
            self.driver.delete_all_cookies()
            self.driver.maximize_window()
        elif browserName == 'Firefox':
            self.driver = webdriver.Firefox()
            self.driver.delete_all_cookies()
            self.driver.maximize_window()
        self.driver.implicitly_wait(30)

    def tearDown(self, browserName):
        self.driver.quit()

    def webPage(self):
        self.driver.get('https://www.yahoo.com')

    def click(self, elemLocator, elemValue):
        elp = elemLocator
        flp = slice(0,2)
        if elp[flp] == 'id':#return by ID
            try:
                self.driver.find_element_by_id(elemValue).click()
            except:
                pass
        elif elp[flp] == 'xp':#return by XPATH
            try:
                self.driver.find_element_by_xpath(elemValue).click()
            except:
                pass


    def sendKeys(self, elemLocator, elemValue, messageValue):
        elp = elemLocator
        flp = slice(0,2)
        if elp[flp] == 'id':#return by ID
            try:
                self.driver.find_element_by_id(elemValue).click()
                self.driver.find_element_by_id(elemValue).clear()
                self.driver.find_element_by_id(elemValue).send_keys(messageValue)
            except:
                pass

        elif elp[flp] == 'xp':#return by XPATH
            try:
                self.driver.find_element_by_xpath(elemValue).click()
                self.driver.find_element_by_xpath(elemValue).clear()
                self.driver.find_element_by_xpath(elemValue).send_keys(messageValue)
            except:
                pass

#test.py file

    from Setup import Actions

class test_case_1: #find element by id

    action = Actions(object)
    action.setUp('Chrome')
    action.webPage()
    action.click('id_of_yahoo_logo', 'uh-logo')
    action.tearDown('Chrome')


class test_case_2: #find element by xpath

    action = Actions(object)
    action.setUp('Chrome')
    action.webPage()
    action.click('xp_of signIn_button', '//*[@id="uh-signin"]')
    action.tearDown('Chrome')

class test_case_3: #login to email

    action = Actions(object)
    action.setUp('Chrome')
    action.webPage()
    action.click('xp_of signIn_button', '//*[@id="uh-signin"]')
    action.sendKeys('id_username_login_inp_field','login-username','deniska')
    action.click('id_of submit_button', 'login-signin')
    action.tearDown('Chrome')

Instead I am trying to pass value for parameters from another file as described by the best practices for data driven testing framework. My next step is to create a data.json file that I will use to map out all elements of the DOM in the following format: "id_login_button":"some id value", "xp_input_field":"some xp value" etc. Can someone, please, help me figure out how to implement this technique?


Solution

  • Here is the simple approach if you want to use the json as your uiRepo.

    sample.json:

    {
        "id_of_yahoo_logo":"uh-logo",
        "xp_of_signIn_button":"//*[@id='uh-signin']",
        "id_username_login_inp_field":"New York",
        "id_of_submit_button":"login-signin"
    }
    

    test.py

    # you have to just specify the name as shown below
    action.click('xp_of_signIn_button)
    

    Reading value in Actions.py:

    import json
    
    #parse json
    with open('sample.json') as f:
        uiRepo = json.load(f)
    
    # update the generic methods to get the property form json
    print(uiRepo['id_of_yahoo_logo'])
    

    Edit 1:setup.py Un-Tested updates

    from   selenium import webdriver
    from   selenium.webdriver.common.by import By
    from   selenium.webdriver.common.keys import Keys
    from   selenium.webdriver.support.ui import Select
    from   selenium.common.exceptions import NoSuchElementException
    from   selenium.common.exceptions import NoAlertPresentException
    import json
    
    class Actions(object):
        # initialize uiRepo
        uiRepo = None
        def __init__(self,driver=None):
            if driver != None:
                self.driver = driver
                # load the uiRepo from json when you init the driver
                with open('sample.json') as repo:
                    uiRepo = json.load(repo)
    
        def setUp(self, browserName):
            browserName = browserName.lower()
            if browserName == 'chrome':
                self.driver = webdriver.Chrome()
            elif browserName == 'safari':
                self.driver = webdriver.Safari()
            elif browserName == 'firefox':
                self.driver = webdriver.Firefox()
            self.driver.delete_all_cookies() #< === moved this line
            self.driver.maximize_window() #< === moved this line
            self.driver.implicitly_wait(30)
    
        def tearDown(self): #< === Removed browser here as you don't need browser name while closing it.
            self.driver.quit()
    
        def webPage(self,url): #< === Added url as param, rather hard code
            self.driver.get(url)
    
        # new method to get the element based on the jsonKey
        def getElement(self, jsonKey):
            locatorStrategy = jsonKey[:2]  # <=== getting first 2 chars to figure out if it's id/xp
            locator = uiRepo[jsonKey]  # < == getting value from json
            ele = None
            try:
                if locatorStrategy == 'id':  # return by ID
                    ele =  self.driver.find_element_by_id(locator).click()  # <=== using the locator got from json
                elif locatorStrategy == 'xp':  # return by XPATH
                    ele =  self.driver.find_element_by_xpath(locator).click()
            except:
                pass
            # if you want you can add additional logic something like highlighting the element
            return ele
    
        def click(self, jsonKey): # < ==== updated method to accept only jsonElementName (Removed the element value param)
            ele = self.findElement(jsonKey)
            ele.click()