I'm trying to make a fixture for cross-browser tests with PyTest. From @pytest.mark.parametrize fixture gets "browser_name" and sets up correct webdriver in internal method. In the end of tests I tried to add a teardowm method to close browser, but I noticed that it just doesn't work. Can anyone help?
In my conftest.py file I have:
import pytest
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.firefox.service import Service as FirefoxService
from selenium.webdriver.edge.service import Service as EdgeService
from webdriver_manager.chrome import ChromeDriverManager
from webdriver_manager.firefox import GeckoDriverManager
from webdriver_manager.microsoft import EdgeChromiumDriverManager
from selenium import webdriver
@pytest.fixture()
def WebDriverFixture(request):
def driverSetup(browser_name):
print("\nStarting browser...\n")
match browser_name:
case "chrome":
options = webdriver.ChromeOptions()
options.add_argument('excludeSwitches')
options.add_argument('--ignore-ssl-errors=yes')
options.add_argument('--ignore-certificate-errors')
options.add_experimental_option("excludeSwitches", ["enable-logging"])
driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()), options=options)
driver.implicitly_wait(10)
return driver
case "firefox":
options = webdriver.FirefoxOptions()
options.add_argument('excludeSwitches')
options.add_argument('--ignore-ssl-errors=yes')
options.add_argument('--ignore-certificate-errors')
options.set_preference("excludeSwitches", "enable-logging")
options.set_preference("dom.disable_beforeunload", True)
driver = webdriver.Firefox(service=FirefoxService(GeckoDriverManager().install()), options=options)
driver.implicitly_wait(10)
return driver
case "edge":
options = webdriver.EdgeOptions()
options.add_argument('excludeSwitches')
options.add_argument('--ignore-ssl-errors=yes')
options.add_argument('--ignore-certificate-errors')
options.accept_insecure_certs = True
driver = webdriver.Edge(service=EdgeService(EdgeChromiumDriverManager().install()), options=options)
driver.implicitly_wait(10)
return driver
def teardown(driverSetup):
driver = driverSetup(browser_name)
print("\nQuitting browser...")
driver.quit()
request.add_finalizer(teardown(driverSetup))
return driverSetup
In test file I have:
import pytest
from pages.login_page import LoginPage
from pages.base_page import BasePage
import time
@pytest.mark.parametrize('browser_name', ['chrome'])
def test_negative_cases(WebDriverFixture, browser_name):
driver = WebDriverFixture(browser_name)
#tests
...
Using yield
is a better option than using return
for your scenario, because you want to go back and perform another action at the end (closing the browser).
I've modified the code (see below) to show a minimally working example that handles the pytest parameterization and closes browsers at the end.
from selenium import webdriver
import pytest
import time
@pytest.fixture
def WebDriverFixture(request):
driver = None
browser_name = request.getfixturevalue("browser_name")
if browser_name.lower() == "chrome":
driver = webdriver.Chrome()
elif browser_name.lower() == "firefox":
driver = webdriver.Firefox()
elif browser_name.lower() == "edge":
driver = webdriver.Edge()
else:
raise Exception("Unknown browser")
yield driver
try:
driver.quit()
except Exception:
pass
@pytest.mark.parametrize('browser_name', ['chrome', 'firefox', 'edge'])
def test_negative_cases(WebDriverFixture, browser_name):
driver = WebDriverFixture
driver.get("https://example.com")
time.sleep(1)
The latest version of selenium
already includes webdriver_manager
now, so you no longer need to add that separately.