Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide a driver_factory - fixture #151

Open
larsrinn opened this issue Jan 30, 2018 · 17 comments
Open

Provide a driver_factory - fixture #151

larsrinn opened this issue Jan 30, 2018 · 17 comments

Comments

@larsrinn
Copy link

larsrinn commented Jan 30, 2018

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 driver fixture
  • 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, module or class

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)

@davehunt
Copy link
Contributor

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.

@larsrinn
Copy link
Author

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

@larsrinn
Copy link
Author

larsrinn commented Feb 3, 2018

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

@abotalov
Copy link

@larsrinn Will be it a breaking change? Calling a session fixture from a function fixture is possible.

@abotalov
Copy link

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".

@BeyondEvil
Copy link
Contributor

Ping @larsrinn Any progress on this?

@tony
Copy link
Member

tony commented Oct 25, 2018

This is the only thing in the way. Without this I can't use pytest-selenium on the project I'm on.

@BeyondEvil
Copy link
Contributor

Could you describe the use case you're faced with @tony ?

That might helps us suggest an alternative approach.

@iramisvalentincapco
Copy link

iramisvalentincapco commented Nov 20, 2018

@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:

@elyezer
Copy link

elyezer commented Nov 29, 2018

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

@tony
Copy link
Member

tony commented Nov 29, 2018

@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.

@elyezer
Copy link

elyezer commented Nov 29, 2018

@tony I will give it a try then. Thank you

@ximon18
Copy link

ximon18 commented Jun 13, 2019

Hi all,

Is there an update on this?

Thanks,

Ximon

@BeyondEvil
Copy link
Contributor

Since this request was made, has there been any changes to pytest that would make the implementation of a driver factory easier? @RonnyPfannschmidt @nicoddemus

@RonnyPfannschmidt
Copy link
Member

If you mean multi scope fixtures, then nope

@BeyondEvil
Copy link
Contributor

If you mean multi scope fixtures, then nope

That or anything else that comes to mind. 🤷‍♂️

@isaulv
Copy link
Contributor

isaulv commented Oct 24, 2020

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants