Python Selenium Test Suite Single Webdriver Instance? - python

I'm having some real issues trying to work out how to get this to work, and I'm sure there are some experts on here who can work it out for me, please :)
So I have a number of test cases in python that all follow on from each other, but are individual scripts, I want to combine these and run them in order, in a single webdriver instance, as they all follow on, but I can't seem to work out how to do it..
I have created a test suite -
import unittest
from Searchfieldreturnscorrectvalue import SearchFieldReturnsCorrectValue
from Navigatetostreetlightprecontentpage import Navigatetostreetlightprecontentpage
class TestSuite(unittest.TestSuite):
def suite():
suite = unittest.TestSuite()
suite.addTest(Searchfieldreturnscorrectvalue('test_searchfieldreturnscorrectvalue'))
suite.addTest(Navigatetostreetlightprecontentpage('test_navigatetostreetlightprecontentpage'))
return suite
if __name__ == "__main__":
unittest.main()
This runs the tests, but the second one fails as it tried to run it in a second firefox instance..
Searchfieldreturnscorrectvalue.py
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 unittest, time, re
class SearchFieldReturnsCorrectValue(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "https://www.XXXXX.com/"
self.verificationErrors = []
self.accept_next_alert = True
def test_search_field_returns_correct_value(self):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_id("edit-search-block-form--2").click()
driver.find_element_by_id("edit-query").clear()
driver.find_element_by_id("edit-query").send_keys("street light")
driver.find_element_by_id("edit-query").send_keys(Keys.ENTER)
for i in range(60):
try:
if self.is_element_present(By.LINK_TEXT, "Street lighting"): break
except: pass
time.sleep(1)
else: self.fail("time out")
try: self.assertEqual("Street lighting", driver.find_element_by_link_text("Street lighting").text)
except AssertionError as e: self.verificationErrors.append(str(e))
def is_element_present(self, how, what):
try: self.driver.find_element(by=how, value=what)
except NoSuchElementException as e: return False
return True
def is_alert_present(self):
try: self.driver.switch_to_alert()
except NoAlertPresentException as e: return False
return True
def close_alert_and_get_its_text(self):
try:
alert = self.driver.switch_to_alert()
alert_text = alert.text
if self.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: self.accept_next_alert = True
def tearDown(self):
self.assertEqual([], self.verificationErrors)
if __name__ == "__main__":
unittest.main()
Navigatetostreetlightprecontentpage.py
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 unittest, time, re
class Navigatetostreetlightprecontentpage(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.verificationErrors = []
self.accept_next_alert = True
def test_navigatetostreetlightprecontentpage(self):
driver = self.driver
driver.find_element_by_link_text("Street lighting").click()
try: self.assertEqual("Street lighting", driver.find_element_by_css_selector("h1.page-title__main__title").text)
except AssertionError as e: self.verificationErrors.append(str(e))
try: self.assertEqual("Report a faulty street light | Cheshire East", driver.title)
except AssertionError as e: self.verificationErrors.append(str(e))
def is_element_present(self, how, what):
try: self.driver.find_element(by=how, value=what)
except NoSuchElementException as e: return False
return True
def is_alert_present(self):
try: self.driver.switch_to_alert()
except NoAlertPresentException as e: return False
return True
def close_alert_and_get_its_text(self):
try:
alert = self.driver.switch_to_alert()
alert_text = alert.text
if self.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: self.accept_next_alert = True
def tearDown(self):
self.assertEqual([], self.verificationErrors)
if __name__ == "__main__":
unittest.main()
I don't know if a test suite is the correct way to do it, or to just get all the tests into one file, but I still would want the "Classes/Tests" to individually report pass/fail, at the moment I can't get that to work, I think it is something to do with the setUp(self) needing to be moved to a setUpModule and shared? But I can't work it out, if someone could please point me in the right direction, I would be very grateful.
Thanks
Update
Example of what I have tired as per comment bellow, still not working..
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 unittest, time, re
class SeleniumTest(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls.driver = webdriver.Firefox()
cls.driver.maximize_window()
#classmethod
def tearDownClass(cls):
cls.driver.close()
cls.driver.quit()
class SearchFieldReturnsCorrectValue(SeleniumTest):
def setUp(cls):
cls.base_url = "https://www.XXXXX.com"
cls.verificationErrors = []
cls.accept_next_alert = True
def test_search_field_returns_correct_value(cls):
driver = cls.driver
driver.get(cls.base_url + "/")
driver.find_element_by_id("edit-search-block-form--2").click()
driver.find_element_by_id("edit-query").clear()
driver.find_element_by_id("edit-query").send_keys("street light")
driver.find_element_by_id("edit-query").send_keys(Keys.ENTER)
for i in range(60):
try:
if cls.is_element_present(By.LINK_TEXT, "Street lighting"): break
except: pass
time.sleep(1)
else: cls.fail("time out")
try: cls.assertEqual("Street lighting", driver.find_element_by_link_text("Street lighting").text)
except AssertionError as e: cls.verificationErrors.append(str(e))
driver.find_element_by_link_text("Street lighting").click()
def is_element_present(cls, how, what):
try: cls.driver.find_element(by=how, value=what)
except NoSuchElementException as e: return False
return True
def is_alert_present(cls):
try: cls.driver.switch_to_alert()
except NoAlertPresentException as e: return False
return True
def close_alert_and_get_its_text(cls):
try:
alert = cls.driver.switch_to_alert()
alert_text = alert.text
if cls.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: cls.accept_next_alert = True
def tearDown(cls):
cls.assertEqual([], cls.verificationErrors)
class Navigatetostreetlightprecontentpage(SeleniumTest):
def setUp(cls):
cls.verificationErrors = []
cls.accept_next_alert = True
def test_navigatetostreetlightprecontentpage(cls):
driver = cls.driver
try: cls.assertEqual("Street lighting", driver.find_element_by_css_selector("h1.page-title__main__title").text)
except AssertionError as e: cls.verificationErrors.append(str(e))
try: cls.assertEqual("Report a faulty street light | Cheshire East", driver.title)
except AssertionError as e: cls.verificationErrors.append(str(e))
def is_element_present(cls, how, what):
try: cls.driver.find_element(by=how, value=what)
except NoSuchElementException as e: return False
return True
def is_alert_present(cls):
try: cls.driver.switch_to_alert()
except NoAlertPresentException as e: return False
return True
def close_alert_and_get_its_text(cls):
try:
alert = cls.driver.switch_to_alert()
alert_text = alert.text
if cls.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: cls.accept_next_alert = True
def tearDown(cls):
cls.assertEqual([], cls.verificationErrors)
if __name__ == "__main__":
unittest.main()
This seems to be running both classes now, but the second class is never able to locate any elements, but the same line in the first class works perfectly.

I am not sure I understood well, but to use a single driver instance, you can use the setupClass class method where you create the driver:
class MyTestClass(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls.driver = webdriver.Firefox()
#classmethod
def tearDownClass(cls):
cls.driver.close()
cls.driver.quit()
def setUp(self):
....
It will still recreate the driver for every new test class, but it does not recreate one for every test (as setUp does).
Personnally I make all my test classes inherit from a SeleniumTest class like this:
class SeleniumTest(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls.driver = webdriver.Firefox()
#classmethod
def tearDownClass(cls):
cls.driver.close()
cls.driver.quit()
class MyTestClass(SeleniumTest):
def setUp(self):
....

import unittest
from selenium import webdriver
from time import sleep
class SeleniumTest(unittest.TestCase):
global driver
#classmethod
def setUpClass(cls):
#getting a common webdriver instance for all your tests for this module
cls.driver = webdriver.Chrome("/Users/sibasish/PycharmProjects/CommonDriverInstance/chromedriver")
cls.driver.get("https://www.google.com")
#classmethod
def tearDownClass(cls):
cls.driver.close()
cls.driver.quit()
class MyTestClass(SeleniumTest):
def setUp(self):
pass
def test_sample1(self):
print("hello1")
self.driver.get("https://www.google.com/")
sleep(4)
def test_sample2(self):
print("hello2")
self.driver.get("https://www.facebook.com/")
sleep(4)

Related

MaxRetryEnteriesExceeded Exception after restarting chromedriver selenium python

I have a script to auto check crypto prices every 5 minutes but I can't let chrome driver opened due to number of reasons, however when I quit it and start it again exception occur
while True:
before_time = time.time()
self.start() # this initialize chromedriver
self.driver.get(self.url)
self.check()
self.quit()
after_time = time.time()
self._counter += 1
self._time.append(round(after_time - before_time, 3))
print(self._timer)
self.delay.custom(self._timer)
This works perfect on first iteration while in the next iterations exception occur
class Selenium:
def __init__(self, webdriver="uc", _user_data_dir=None, _incognito=False, _proxy_server=None,
load_full=False, _timeout=30, _zoom=125):
assert not _incognito or _user_data_dir is None, "You can't use profile in incognito mode!"
self.driver = None
self.wait = None
self.webdriver = webdriver
self.timeout = _timeout
self.proxy = _proxy_server
self.data_dir = _user_data_dir
self.incognito = _incognito
self.load_type = load_full
self.zoom = _zoom / 100
def start(self):
options = Options()
options.add_argument("--start-maximized")
options.add_argument(f"--force-device-scale-factor={self.zoom}")
options.add_argument(f"--high-dpi-support={self.zoom}")
if not self.load_type:
options.page_load_strategy = "none"
if self.proxy is not None:
options.add_argument(f"--proxy-server=socks5://{self.proxy}:1080")
if self.data_dir is not None:
options.add_argument(f"--user-data-dir={self.data_dir}")
if self.incognito:
options.add_argument(f"--incognito")
if self.webdriver == "uc":
self.driver = uc.Chrome(options=options, use_subprocess=True, suppress_welcome=True)
elif self.webdriver.lower() == "chrome":
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
self.driver = webdriver.Chrome(service=service(__chrome=True), options=options)
elif self.webdriver.lower() == "firefox":
self.driver = webdriver.Chrome(service=service(__gecko=True), options=options)
else:
raise NotImplementedError(f"{self.webdriver} is not implemented yet!")
self.wait = WebDriverWait(self.driver, self.timeout)
def slow_type(self, element, content):
for x in content:
element.send_keys(x)
self.delay.custom(self.speed)
def get(self, url):
self.driver.get(url)
def quit(self):
self.driver.quit()
def refresh(self):
self.driver.refresh()

AssertTrue missing 1 required positional argument

I am trying to assert the presence of an element and I can make it work but now in the way that I would like.
I have a common functions file: -
from selenium.common.exceptions import NoSuchElementException
def is_element_present_common(self, how, what):
try:
self.driver.find_element(by=how, value=what)
except NoSuchElementException as e:
return False
return True
...and my main file: -
import unittest
from Common import common_functions, initialisation, login
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as ec
from selenium.common.exceptions import NoSuchElementException
class QuickTestPlanLogin(unittest.TestCase):
def setUp(self):
self.driver = initialisation.start_webdriver()
self.driver = initialisation.start_sap(self.driver)
def tearDown(self):
self.driver.close()
def is_element_present(self, how, what):
try:
self.driver.find_element(by=how, value=what)
except NoSuchElementException as e:
return False
return True
def test_login(self):
wait = initialisation.wait_for(self.driver)
self.driver = login.default_login(self.driver, "username", "password")
# self.assertTrue(self.is_element_present(By.ID, "my-projects-table_info"))
# self.assertTrue(common_functions.is_element_present_common(By.ID, "my-projects-table_info"))
There are two assert statements. If I run the first one it works fine, but it is calling the is_element_present function which I do not want. I would like to call the is_element_present_common function from the common_functions file. Every time I run the second assert statement I get the following error: -
TypeError: is_element_present() missing 1 required positional argument: 'what'
I know I am missing something very simple....
Change the function definition to :
def is_element_present_common(how, what):
And
Change the call to is_element_present_common function as :
self.assertTrue(common_functions.is_element_present_common(By.ID, "my-projects-table_info"))

repetitive global variable and try except in python unit tests

I have started using Python Selenium and wrote a script shown below.
This prints a return code linked to the test that fails (test01, test02, test03, ..).
Ignore that each test is checking the same thing.
I'm just trying to understand if there's a cleaner way to write the tests because each one repetitively declares global res, and then has a try/except block.
Could anyone offer some advice on how to improve this please?
# global variable for return code. Zero is success.
res=0
#atexit.register
def send_health():
print ("res=%s") % res
class Login(unittest2.TestCase):
#classmethod
def setUpClass(inst):
binary = FirefoxBinary('C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe')
inst.driver = webdriver.Firefox(firefox_binary=binary)
inst.base_url = "https://stackoverflow.com"
def test01(self):
global res
driver = self.driver
try:
self.assertEqual("Ask a Question", driver.title)
except Exception,e:
print ("Exception: %s" % e)
driver.save_screenshot('screenshot_test01.png')
res=1
return
def test02(self):
global res
driver = self.driver
try:
self.assertEqual("Ask a Question", driver.title)
except Exception,e:
print ("Exception: %s" % e)
driver.save_screenshot('screenshot_test02.png')
res=2
return
def test03(self):
global res
driver = self.driver
try:
self.assertEqual("Ask a Question", driver.title)
except Exception,e:
print ("Exception: %s" % e)
driver.save_screenshot('screenshot_test03.png')
res=3
return
if __name__ == "__main__":
unittest2.main()
There is no need for global variables here at all. You are inside a class; use self.res throughout.
That's exactly what setUp instance method is for, quite similar to setUpClass method that is run once per test class.
def setUp(self):
# this code will be executed before each and every test
self.res = 0
def tearDown(self):
# this code will be executed post each and every test.
By the way, why are you using global variables? There's no need for them. In fact, there's seldom a valid rationale for using globals. Moreover, tests need to be isolated and independent, using global variables would violate that rule.
Thanks for the tips above. I've reduced the code down to this version which hopefully looks cleaner and more standard:
class Login(unittest2.TestCase):
#classmethod
def handleError(self, e, res):
print ("Test failed with exception: %s" % e)
self.result = res
sys.exit()
#classmethod
def setUpClass(self):
binary = FirefoxBinary('C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe')
self.driver = webdriver.Firefox(firefox_binary=binary)
self.base_url = "https://stackoverflow.com"
self.result = 0
def test01(self):
driver = self.driver
try:
self.assertEqual("Ask a Question", driver.title)
except Exception,e:
self.handleError(e, 1)
def test02(self):
driver = self.driver
try:
self.assertEqual("Ask a Question", driver.title)
except Exception,e:
self.handleError(e, 2)
def test03(self):
driver = self.driver
try:
self.assertEqual("Ask a Question", driver.title)
except Exception,e:
self.handleError(e, 3)
#classmethod
def tearDownClass(self):
self.driver.quit()
print ("res=%s") % self.result
if __name__ == "__main__":
unittest2.main()

Using arg parser in python in another class

I'm trying to write a test in Selenium using python,
I managed to run the test and it passed, But now I want add arg parser so I can give the test a different URL as an argument.
The thing is that my test is inside a class,
So when I'm passing the argument I get an error:
app_url= (args['base_url'])
NameError: global name 'args' is not defined
How can I get args to be defined inside the Selenium class?
This is my code:
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoAlertPresentException
from selenium import webdriver
import unittest, time, re
import os
import string
import random
import argparse
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
return ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(8))
agmuser = id_generator()
class Selenium(unittest.TestCase):
def setUp(self):
chromedriver = "c:\chromedriver.exe"
os.environ["webdriver.chrome.driver"] = chromedriver
self.driver = webdriver.Chrome(chromedriver)
app_url = (args['base_url'])
#app_url= "http://myd-vm16635.fufu.net:8080/"
print "this is the APP URL:" + ' ' + app_url
self.base_url = app_url
self.verificationErrors = []
self.accept_next_alert = True
def test_selenium(self):
#id_generator.user = id_generator()
driver = self.driver
driver.get(self.base_url + "portal/")
driver.find_element_by_css_selector("span").click()
driver.find_element_by_id("j_loginName").clear()
driver.find_element_by_id("j_loginName").send_keys(agmuser)
driver.find_element_by_id("btnSubmit").click()
driver.find_element_by_link_text("Login as" + ' ' + agmuser).click()
driver.find_element_by_css_selector("#mock-portal-Horizon > span").click()
# driver.find_element_by_id("gwt-debug-new-features-cancel-button").click()
# driver.find_element_by_xpath("//table[#id='gwt-debug-module-dropdown']/tbody/tr[2]/td[2]").click()
# driver.find_element_by_id("gwt-debug-menu-item-release-management").click()
def is_element_present(self, how, what):
try: self.driver.find_element(by=how, value=what)
except NoSuchElementException as e: return False
return True
def is_alert_present(self):
try: self.driver.switch_to_alert()
except NoAlertPresentException as e: return False
return True
def close_alert_and_get_its_text(self):
try:
alert = self.driver.switch_to_alert()
alert_text = alert.text
if self.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: self.accept_next_alert = True
def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)
if __name__ == "__main__":
#####################******SCRIPT PARAMS****;**###################################
# these values can be changed type 'python selenium_job.py --help' for assistance
##################################################################################
parser = argparse.ArgumentParser(description='DevOps team - Sanity test')
parser.add_argument('-b', '--base_url', help='base_url', default="http://myd-vm16635.fufu.net:8080/")
args = vars(parser.parse_args())
unittest.main()
Put the parser = argparse.ArgumentParser(...) and parser.add_argument() outside if __name__ == "__main__": so that it always gets created but not evaluated. Keep args = vars(parser.parse_args()) inside __main__.
That way you can import it from the file like from selenium_tests import parser and then in your other script, do parser.parse_args().
And a cleaner way to do it is to create a function which returns the parser, like:
def get_parsed_args():
parser = argparse.ArgumentParser(...)
parser.add_argument(...)
# etc.
args = parser.parse_args()
return args
# or just...
return parser.parse_args()
#and then call that in the main program:
if __name__ == '__main__':
args = get_parsed_args()
# etc.
And in other scripts which you want to import it into, do
from selenium_tests import get_parsed_args
if __name__ == '__main__':
args = get_parsed_args()
# etc.

Checking if HTML element exists with Python Selenium

I am trying to check if an element exists on an HTML page with Selenium/Python.
This is my function:
class runSelenium(object):
def __init__(self):
# define a class attribute
self.driver = webdriver.Firefox()
def isElementPresent(self, locator):
try:
self.driver.find_element_by_xpath(locator)
except NoSuchElementException:
print ('No such thing')
return False
return True
def selenium(self):
self.driver.get("https://somepage.com")
isElement = self.isElementPresent("//li[#class='item'][6]")
isElement1 = str(isElement)
if __name__ == '__main__':
run = runSelenium()
run.selenium()
I am trying to pick the result with a Boolean value but with no luck:
isElement = self.isElementPresent("//li[#class='item'][6]")
What am I missing here?
You need to un-indent the last code block:
class runSelenium(object):
def __init__(self):
# define a class attribute
self.driver = webdriver.Firefox()
def isElementPresent(self, locator):
try:
self.driver.find_element_by_xpath(locator)
except NoSuchElementException:
print ('No such thing')
return False
return True
def selenium(self):
self.driver.get("https://somepage.com")
isElement = self.isElementPresent("//li[#class='item'][6]")
isElement1 = str(isElement)
if __name__ == '__main__':
run = runSelenium()
run.selenium()
So I restarted the IDE (Visual Studio 2013) and it works now fine.. The code is correct 100%

Categories