i would like to know why this code opens mozilla twice, and why it doesn´t close it when finishes. Furthermore, i don´t understand 100% why login is a class with a function, and not a function directly.
> import unittest
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class LoginDetails(object):
def __init__ (self):
self.driver = webdriver.Firefox()
def logindetails(self, username, password):
driver = self.driver
driver.maximize_window()
driver.get("https://miclaro.claro.com.ar/")
driver.implicitly_wait(30)
driver.find_element_by_id("_58_login_movil").send_keys(username)
driver.find_element_by_id("_58_password_movil").send_keys(password)
driver.find_element_by_id("btn-home-login").click()
# Login Success
class TestLogin(unittest.TestCase):
def setUp(self):
self.ld = LoginDetails()
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
def test_sr_Login(self):
self.ld.logindetails("user", "pass")
def tearDown(self):
self.driver.close()
if __name__ == "__main__":
#import sys;sys.argv = ['', 'Test.testName']
unittest.main()
Thank you very much!
This is because you instantiate webdriver twice - once inside the TestCase and once inside the LoginDetails class.
Why the other answer is not entirely correct
The WebDriver should not be controlled by the LoginDetails class in this case. LoginDetails class is very close to a Page Object notation representation and, hence, should be given the driver "from outside". Plus, opening browser in one class and closing it in the other is making the code close to "Spaghetti".
Better solution
Control the webdriver from the TestCase class and "share" with the LoginDetails:
import unittest
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class LoginDetails(object):
def __init__ (self, driver):
self.driver = driver
def logindetails(self, username, password):
driver = self.driver
driver.maximize_window()
driver.get("https://miclaro.claro.com.ar/")
driver.implicitly_wait(30)
driver.find_element_by_id("_58_login_movil").send_keys(username)
driver.find_element_by_id("_58_password_movil").send_keys(password)
driver.find_element_by_id("btn-home-login").click()
class TestLogin(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.ld = LoginDetails(self.driver)
def test_sr_Login(self):
self.ld.logindetails("user", "pass")
def tearDown(self):
self.driver.close()
Firefox opens twice
In your test self.ld = LoginDetails() runs the __init__ function of LoginDetails() which in turn runs webdriver.Firefox() then you issue the same in the next line in the test case. That is why Firefox opens twice.
Firefox does not close
For the same reason as above Firefox is not closed. The tearDown of your test case only closes the instance of webdriver.Firefox() defined in the test case itself not the one opened via the __init__ function of the class.
Why LoginDetails is a class
LoginDetails is a class in this case to keep webdriver.Firefox() persistent throughout your code. If it would be a function you would open one Firefox session each time you run the function. Unless you specify webdriver.Firefox() outside the function and then pass it to the function.
Corrected Code
The following code uses the class functionality:
import unittest
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class LoginDetails(object):
def __init__ (self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
def logindetails(self, username, password):
self.driver.maximize_window()
self.driver.get("https://miclaro.claro.com.ar/")
self.driver.implicitly_wait(30)
self.driver.find_element_by_id("_58_login_movil").send_keys(username)
self.driver.find_element_by_id("_58_password_movil").send_keys(password)
self.driver.find_element_by_id("btn-home-login").click()
def __del__(self):
''' ADDED based on comment by alecxe '''
self.driver.close()
class TestLogin(unittest.TestCase):
def setUp(self):
self.ld = LoginDetails()
def test_sr_Login(self):
self.ld.logindetails("user", "pass")
def tearDown(self):
# driver is closed by LoginDetails
pass
if __name__ == "__main__":
#import sys;sys.argv = ['', 'Test.testName']
unittest.main()
Related
I have a fixture file.
import pytest
from selenium.webdriver.chrome.options import Options as chrome_options
from driver.singleton_driver import WebDriver
#pytest.fixture
def get_chrome_options():
options = chrome_options()
options.add_argument('chrome')
options.add_argument('--start-maximized')
options.add_argument('--window-size=1920,1080')
options.add_argument('--incognito')
return options
#pytest.fixture
def get_webdriver(get_chrome_options):
options = get_chrome_options
driver = WebDriver(options).driver
return driver
#pytest.fixture(scope='function')
def setup(request, get_webdriver):
driver = get_webdriver
if request.cls is not None:
request.cls.driver = driver
yield driver
driver.close()
File with my tests
import pytest
#pytest.mark.usefixtures('setup')
class TestSteamPages:
def test_first(self):
self.driver.get('https://www.google.com/')
def test_second(self):
self.driver.get('https://www.google.com/')
As I understand it, after the first test, the function in the driver.close() fixture is triggered. But when the second test is run, the fixture does not restart the webdriver. An error
venv/lib/python3.10/site-packages/selenium/webdriver/remote/errorhandler.py:243: InvalidSessionIdException
============================================================================== short test summary info ==============================================================================
FAILED tests/test_first.py::TestSteamPages::test_second -
selenium.common.exceptions.InvalidSessionIdException: Message: invalid session id
ERROR tests/test_first.py::TestSteamPages::test_second - selenium.common.exceptions.InvalidSessionIdException: Message: invalid session id
For the driver, I use the Singleton pattern
from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager
class WebDriver:
class __WebDriver:
def __init__(self, options):
self.driver = webdriver.Chrome(options=options, service=ChromeService(ChromeDriverManager().install()))
driver = None
def __init__(self, options):
if not self.driver:
WebDriver.driver = WebDriver.__WebDriver(options=options).driver
The driver is not reinitialized because of the singleton. WebDriver.driver is initialized before first test, so in the next time setup is running if not self.driver is False, because self.driver is not None anymore.
If you want to initialize the WebDriver every test don't use singleton
#pytest.fixture
def get_webdriver(get_chrome_options):
options = get_chrome_options
driver = webdriver.Chrome(options=options, service=ChromeService(ChromeDriverManager().install()))
return driver
If you do want to initialize the WebDriver only once you can change fixtures scope to 'class' (for all tests in TestSteamPages) or even move it to conftest.py with scope 'session' for one driver instance for all the test. Note that in this case all the fixtures need to have scope='class'
#pytest.fixture(scope='class')
def setup(request, get_webdriver):
driver = get_webdriver
if request.cls is not None:
request.cls.driver = driver
yield driver
driver.close()
I've been looking for a solution to inherit the methods of the python selenium webdriver class so that I can extend/modify its behaviour. I have not found one that work.
For instance, I want to inherit all the methods of the chrome webdriver but extend the .get() method (i.e. the method to load a url). This is my current approach:
from selenium import webdriver
from selenium.common.exception import TimeoutException
class CustomDriver:
def __init__(self, browser):
if browser.lower() == 'chrome'
self.driver = webdriver.Chrome()
def get_url(self, url):
try:
self.driver.get(url)
except TimeoutException:
self.driver.quit()
This methods works but it does not inherit the general webdriver methods like driver.quit(). In fact, if I do the following:
mydriver = CustomDriver('Chrome')
mydriver.quit()
I get the error: 'Custom driver' object has no attribute quit.
Has any of you any suggestions?
ps: I'm new to python.
quit() is from webdriver methods and you are importing it from selenium module, and you have created a object self.driver for the webdriver.Chrome()
so you can't use webdriver method on created class object that is the reason why you are getting No Attribute Error : 'Custom driver' object has no attribute quit
One way of obtaining inheritance is by declaring respective method inside the class and inherit those methods outside.
Refer this document: https://www.geeksforgeeks.org/web-driver-methods-in-selenium-python/
Below is the code that would work
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
class CustomDriver:
def __init__(self, browser):
if browser.lower() == 'chrome':
self.driver = webdriver.Chrome()
def exit_browser(self):
self.driver.quit()
def get_url(self, url):
try:
self.driver.get(url)
except TimeoutException:
self.driver.quit()
mydriver = CustomDriver('Chrome')
mydriver.get_url("https://www.google.com/")
mydriver.exit_browser()
I am trying to inherit browser class in test. Can someone please point out what am i doing wrong here. I am new to python
This is my test class where I am trying to inherit browser class
import unittest
from Configurations.Browser import Browser
class GoogleTest(Browser):
def test_homepage(self):
driver = self.driver
self.driver.implicitly_wait(10) self.driver.find_element_by_xpath("/html/body/div/div[4]/form/div[2]/div[1]/div[1]/div/div[2]/input").send_keys("Test")
Browser.py:
import unittest
from selenium import webdriver
class Browser(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox(executablepath=r"C:\Setups\Selenium\Drivers\geckodriver.exe")
self.driver.implicitly_wait(10)
self.driver.maximize_window()
self.driver.get("https://www.google.com")
def tearDown(self):
if(self.driver != None):
self.driver.close()
self.driver.quit()
if __name__ == '__main__':
unittest.main()
You have to change the "excutablepath" to "executable_path".(Browser.py)
like this
self.driver = webdriver.Firefox(executable_path=r"C:\Setups\Selenium\Drivers\geckodriver.exe")
I have a select box on my page. I click on it to expand it and all values are displayed. Now i take screenshot, but in screenshot, select box is not expanded. Please check.
Code:
import unittest
from selenium import webdriver
import datetime
from selenium.webdriver.firefox.firefox_profile import FirefoxProfile
from selenium.common.exceptions import NoSuchElementException
from unittest import TestCase
import re
import time
import autoit
url="https://www.facebook.com"
class SprintTests(unittest.TestCase):
def setUp(self):
self.verificationErrors = []
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.driver.maximize_window()
self.driver.get(url)
def test_offer_1(self):
a=self.driver.find_element_by_id("day")
a.click()
time.sleep(5)
self.driver.save_screenshot("res.jpg")
def tearDown(self):
self.driver.quit()
if __name__ == '__main__':
unittest.main(verbosity=2)
Image generated by my code:
Expected Image:
With the given situation, it is expected to behave in this way.
When you perform save_screenshot on driver object, the driver object is now busy getting the screenshot for you instead of keeping the select menu open.
One possible solution is that you launch the save_screenshot method in different thread.
I have a functional test 'y1.py' which I have exported from the selenium IDE. It looks like:
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
import unittest, time, re
class Y1(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "https://www.yahoo.com/"
self.verificationErrors = []
self.accept_next_alert = True
def test_y1(self):
driver = self.driver
driver.get(self.base_url)
driver.find_element_by_link_text("Weather").click()
driver.save_screenshot('out11.png')
def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)
if __name__ == "__main__":
unittest.main()
I am trying to call this directly from within a python/django function. while investigating this I came across: AttributeError 'module' object has no attribute 'runserver' in django, where Udi states:
Are you trying to run unitest and selenium from a view? You should
consider launching a second process for that.
How can I do this?
You can start django server as new process with subprocess module.