Provide a driver_factory - fixture
Having a driver_factory fixture additionally to the driver factory would be very useful for me (similarly to the pattern of tmpdir and tmpdir_factory):
- Sometimes I need two seperate browser windows within one test. I couldn't find a way how to do that with the
driverfixture - For some of our tests it would be fine, if the browser window is not closed and reopened between running them, in order to save time. However, this requires the fixture to be of a scope of
session,moduleorclass
I hacked a modification of the driver fixture in my conftest.py. Do you think this would be reasonable to include into pytest-selenium. If so, I'm happy to create pull request.
@pytest.fixture
def driver_factory(request, driver_class, driver_kwargs):
"""
Returns a factory function that returns a WebDriver instance when called,
based on options and capabilities
"""
request.node.drivers = []
def factory():
driver = driver_class(**driver_kwargs)
request.node.drivers.append(driver)
event_listener = request.config.getoption('event_listener')
if event_listener is not None:
# Import the specified event listener and wrap the driver instance
mod_name, class_name = event_listener.rsplit('.', 1)
mod = __import__(mod_name, fromlist=[class_name])
event_listener = getattr(mod, class_name)
if not isinstance(driver, EventFiringWebDriver):
driver = EventFiringWebDriver(driver, event_listener())
return driver
yield factory
for driver in request.node.drivers:
driver.quit()
@pytest.fixture
def driver(driver_factory):
return driver_factory()
Usage:
def test_multiple_windows(driver_factory):
driver1 = driver_factory()
driver2 = driver_factory()
# further test content
The possibility to use the driver_factory fixture in class-based-fixtures is not given yet, because the driver_class and driver-kwargs fixtures are function-scoped. But I don't see a reason why this couldn't be changed (which would also result in (slightly) faster running tests)
Hi @lmr2391, thanks for raising this. I would certainly be interested in reviewing a patch that adds support for multiple browser instances per test. I think there are some interested questions that this brings up, for example what if you wanted to use different browsers? We'd also need to ensure that the HTML report clearly distinguished the driver logs and debug content for each of the drivers when there's more than one. Perhaps we could provide an option to name/label the instances?
Regarding sharing browsers between tests, this is something I discourage due to it making tests less deterministic. I know it's a popular request though, so I'm okay with accepting a pull request that makes it easier for users to do (I just don't want it to be the default). It also raises the question of how to manage the driver logs and debug in the HTML report.
Actually I can't think of a usecase for multiple, different browsers per test. I need to have two browser instances in order to test access to and sharing of certain objects. However, this is totally "browser agnostic". Up to my understanding running test with different browsers is only a requirement if you want to ensure whether some browsers render your content in some strange manner. And actually that's an issue I didn't experience for quite a while, at least if you're not checking against legacy browsers.
I didn't think about the logs and HTML report, though. I'll dive into that. Regarding naming: I'd propose an optional parameter to driver_factory. If it is not set, the name will be some random hash.
I agree to your concerns about sharing browsers between tests. However, I think there are some perfectly valid use cases. For example if you're sure that your tests don't change the state of the frontend application, it can assist you with writing shorter and more specific test functions. Browser setup and teardown take quite a while - at least to me this is an unwelcome incentive to test several things in one test function. And again, I didn't think about reporting yet
So I took a closer look at these ideas. Switching to class or session based fixture is not that easy. Because the driver fixture makes use of the driver_kwargs fixture, this would require to also change capabilities, driver_args, driver_kwargs, driver_log, driver_path, driver_factory, chrome_options, firefox_options and firefox_profile to be session scoped. This would cause breaking changes for everybody who redefined any of these fixtures. I don't think the benefits outweigh that. Also the gathering of screenshots, logs, etc. doesn't work anymore without any changes. However, I think that issue could be solved, even though I didn't take a closer look.
But I'm still working on a proposal for having multiple browsers per test
@larsrinn Will be it a breaking change? Calling a session fixture from a function fixture is possible.
Btw, if you just want another window (rather than browser instance) you can open window using JS and switch to it using Webdriver's "switch to window".
Ping @larsrinn Any progress on this?
This is the only thing in the way. Without this I can't use pytest-selenium on the project I'm on.
Could you describe the use case you're faced with @tony ?
That might helps us suggest an alternative approach.
@BeyondEvil I recently researched into adapting pytest-selenium to function in multiple fixture scopes (session, module, class, etc) due to a parallel use-case to @larsrinn. I came to the same conclusion that due to pytest's fixture limitations this type of "brute force" approach to a multi-scope implementation would require a massive refactor of pytest-selenium. This may even be impossible due to all of the pytest builtin fixtures being function-scoped (monkeypatch(), tmp(), and tmp_dir() among others).
However, I believe other implementations of such a multi-scope refactor is possible with less effort (and less risk of breaking) by either:
- Building off of @larsrinn's fixture factory idea and applying it to all of the currently defined fixtures and builtins OR
- Abstracting the actual implementation of each fixture into separate python functions and defining wrapper fixtures with the desired scope (session, module, etc.) as suggested here: https://github.com/pytest-dev/pytest/issues/2334
I've been studying the pytest-selenium source code and having all those aforementioned fixtures makes kinda of hard to allow a browser to be created on multiple scopes.
I think the browser_factory is a good idea, specially because it is the same thing that the tmpdir fixture does. tmpdir offers a factory that allows creating temporary directories on different scopes and as needed.
With all that said, if a browser factory is added to pytest-selenium, then the function scoped fixture could be refactored to use it. For the other scopes it will be a matter of the user to instantiate a browser (like the tmpdir factory). So the factory would be a session scoped and this allows it to be used in any other scope.
I would like to know if there is any work in progress code so maybe I could help. Or if I should give it a try starting fresh?
Thank you
@elyezer If you'd like to make a PR, i think it's all clear to go. Nobody else seems to have traction at the moment.
@tony I will give it a try then. Thank you
Hi all,
Is there an update on this?
Thanks,
Ximon
Since this request was made, has there been any changes to pytest that would make the implementation of a driver factory easier? @RonnyPfannschmidt @nicoddemus
If you mean multi scope fixtures, then nope
If you mean multi scope fixtures, then nope
That or anything else that comes to mind. 🤷♂️
Function callable introduced in Pytest 5.2 may make multi scope fixtures possible. In the past I used tricks to have tests switch between live browser for all tests versus start/close browser per test.