Search code examples
pythonseleniumflaskpytestliveserver

Flask keep live server working for tests (Selenium)


First of all I am aware of flask-testing library with LiveServerTestCase class but it hasn't updated since 2017 and GitHub full of issues of it not working neither on Windows or MacOs and I haven't found any other solutions.

I am trying to write some tests for flask app using selenium to validate FlaskForms inside this app.

Simple test like this:

def test_start(app):
    driver.get("http://127.0.0.1:5000/endpoint")
    authenticate(driver)

falls on selenium.common.exceptions.WebDriverException: Message: unknown error: net::ERR_CONNECTION_REFUSED error. (As far as I understood in my case app creates in @pytest.fixtures and immediately shuts down and I need to find a way to keep it running for the whole test duration)

My question is: Is it possible to to create some live server in each test that will remain working so I could call API endpoints via selenium?

Simple fixtures if it helps:

@pytest.fixture
def app():
    app = create_app()
    ...
    with app.context():
        # creating db
        ...
    yield app

also:

@pytest.fixture
def client(app):
    """Test client"""
    return app.test_client()

Solution

  • Finally got it all working. My conftest.py

    import multiprocessing
    import pytest
    
    from app import create_app
    
    
    @pytest.fixture(scope="session")
    def app():
        app = create_app()
        multiprocessing.set_start_method("fork")
        return app
    
    
    @pytest.fixture
    def client(app):
        return app.test_client()
    

    Important note that using python <3.8 line multiprocessing.set_start_method("fork") is not necessary (as far as I understood in v.3.8 they refactored multiprocessing module so further upon without this line you would get pickle Error on windows and Mac).

    And one simple test looks like

    def test_add_endpoint_to_live_server(live_server):
        @live_server.app.route('/tests-endpoint')
        def test_endpoint():
            return 'got it', 200
    
        live_server.start()
    
        res = urlopen(url_for('.te', _external=True))# ".te is a method path I am calling"
        assert  url_for('.te', _external=True) == "some url"
        assert res.code == 200
        assert b'got it' in res.read()
    

    Also I am using url_for. The point is every time live server starts on a random port and url_for function generates url with correct port internally. So now live server is running and it is possible to implement selenium tests.