I am new in automation testing. I am learning automation using selenium with python(page object model). From learning YouTube I see that, log in is done for every test case, which is redundant. I would like to login once and execute for multiple test case. This is a sample code.
tests/test_dashboard.py
class TestDashboard:
def test_dashboard(self, setup):
self.driver = setup
self.driver.get(self.base_url)
self.lp = Login(self.driver)
self.lp.set_email(self.user_email)
self.lp.set_password(self.user_password)
self.lp.sign_in()
def test_dashboard_checking_fire(self, setup):
self.driver = setup
self.driver.get(self.base_url)
# self.driver.maximize_window()
self.lp = Login(self.driver)
self.lp.set_email(self.user_email)
self.lp.set_password(self.user_password)
self.lp.sign_in()
You see, for 2 teset cases i have to execute log in everytime. How I can login once and execute that 2 test cases at once? I am using pytest framework.How to do this with pytest. There is a setup method.
tests/conftest.py
#pytest.fixture()
def setup(browser):
if browser == "chrome":
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
elif browser == "firefox":
driver = webdriver.Firefox(service=Service(GeckoDriverManager().install()))
else:
driver = webdriver.Edge(service=Service(EdgeChromiumDriverManager().install()))
return driver
Finally, I solve my Problem. I update my setup function like this:
#pytest.fixture(scope="class", autouse=True)
def setup(request, browser, url):
global driver
# my code
request.cls.driver = driver
yield
driver.close()
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()
#pytest.fixture(autouse=True, scope="class")
def test_setup():
global driver
driver = webdriver.Chrome(executable_path="D://chromedriver_win32//chromedriver.exe")
driver.implicitly_wait(10)
driver.maximize_window()
return driver
Use this, it will close the window for you
#pytest.fixture(autouse=True, scope="class")
def test_setup():
global driver
driver = webdriver.Chrome(executable_path="D://chromedriver_win32//chromedriver.exe")
driver.implicitly_wait(10)
driver.maximize_window()
driver.close()
return driver
The pytest documentation covers this
https://docs.pytest.org/en/6.2.x/fixture.html#teardown-cleanup-aka-fixture-finalization
“Yield” fixtures yield instead of return. With these fixtures, we can
run some code and pass an object back to the requesting fixture/test,
just like with the other fixtures. The only differences are:
return is swapped out for yield.
Any teardown code for that fixture is placed after the yield.
#pytest.fixture(autouse=True, scope="class")
def test_setup():
driver = webdriver.Chrome(executable_path="D://chromedriver_win32//chromedriver.exe")
driver.implicitly_wait(10)
driver.maximize_window()
yield driver
# teardown code
driver.close()
I am using below fixture in conftest.py for open and close browser :
conftest.py:
#pytest.fixture(scope='session')
def browser():
print("Setting up webdriver connection...")
global driver
if driver is None:
profile = webdriver.FirefoxProfile()
profile.accept_untrusted_certs = True
profile.set_preference("network.proxy.type",1)
driver = webdriver.Firefox(firefox_profile=profile)
driver.maximize_window()
yield driver
driver.quit()
print("Webdriver connection closed..")
In my Test Class I have below step test_login :
def test_login(self, browser):
login_page = pagep.LoginPage(browser)
login_page.login('hptest376#gmail.com', "test12345*")
login_page.login('user', "pwd")
assert "Sum" in browser.title
And after test_login I have one more test step in my Test Class:
def test_ppt(a):
a=12
print a
Issue : I am getting error in fixture at driver.quit() and browser is not closing.
If I remove the "test_ppt(a)" step after "test_login(self, browser)" then the test runs fine.
Want to know what i need to update in my fixture "browser()" so that driver.quit() is executed.
Changed the scope of fixture to 'function' and the test is passing now.
#pytest.fixture(scope='function')
def browser():
I have a test in Selenium IDE with Flow Control which submits a form and repeats the process with label start until I stop the app.
I have exported my code into python WebDriver.
Unfortunately my test only runs once.
How can I duplicate this process on python.
class Buy(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "https://test.mydomain.com"
def test_buy(self):
driver = self.driver
driver.get(self.base_url + "/Form")
Select(driver.find_element_by_id("DropDownOne")).select_by_visible_text("BLUE")
Select(driver.find_element_by_id("DropDownTwo")).select_by_visible_text("LIGHT")
driver.find_element_by_id("Quantity").send_keys("10")
driver.find_element_by_id("Button").click()
So my setup for running Safari .py tests is a little different than those for Chrome and FireFox (examples below). That being said, the tearDown for Safari must be different, but I cannot find any examples or figure it out.
Chrome setup example:
class ChromeAllLinks(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.implicitly_wait(30)
self.base_url = "https://test.foo.com/"
self.verificationErrors = []
self.accept_next_alert = True
Safari setup example:
class SafariAllLinks(unittest.TestCase):
def setUp(self):
import webbrowser
browser = webbrowser.get('safari')
browser.open("https://test.foo.com/")
self.verificationErrors = []
self.accept_next_alert = True
So of course the tearDown for them should be different as well.
Chrome tearDown being used (which works fine of course):
def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)
And I can show what I am trying for the Safari tearDown, but it isn't working:
def tearDown(self):
browser = webbrowser.quit('safari')
Here is the error being thrown. Says not defined, but it is!
NameError: global name 'webbrowser' is not defined