Repository: pytest-dev/pytest-django

Issue:
Support StaticLiveServerTestCase (new in django 1.7)
Currently when using the `live_server` fixture, one needs to have run `collectstatic` before if one wants to do stuff like selenium tests. This is due to:

https://docs.djangoproject.com/en/1.7/howto/static-files/#testing

> django.contrib.staticfiles.testing.StaticLiveServerCase is new in Django 1.7. Previously its functionality was provided by django.test.LiveServerTestCase.

The question is whether the current `live_server` fixture should be expanded to support this, or a new fixture (`static_live_server` for instance) should be created. Maybe the latter is best for backwards compatibility with django < 1.7.



Discussion:
:+1: 
Running `./manage.py collectstatic` once is the workaround, any other workarounds?

@pelme Any new news about this issue? Should I look into this? Do you have an idea how to fix this?

static_live_server is inconvenient rather than just live_server, but so is importing from django.contrib.staticfiles.testing.StaticLiveServerCase.

Adding static_live_server or live_server_static is probably the best idea, to follow Django as close as possible. This needs to be properly documented and highlighted in the documenation, most people will want to use the live server with static files most of the time.

@bh You are very welcome to work in this.

My workaround was monkeypatching _django_test_environment in conftest.py (patch below) as setting debug = true removes the need for collectstatic or any other workarounds. Any better fix for this would be awesome.

part of my conftest.py:

``` python

from pytest_django.lazy_django import django_settings_is_configured


@pytest.fixture(autouse=True, scope='session')
def _django_test_environment(request):
    """
        overwrite pytest_django/plugin.py
    """
    if django_settings_is_configured():
        from django.conf import settings
        from pytest_django.compat import (setup, setup_test_environment,
                                          teardown_test_environment)
        settings.DEBUG = True  # OVERWRITEN CONFIG
        setup()

        setup_test_environment()
        request.addfinalizer(teardown_test_environment)
```


Resolving patch:
diff --git a/pytest_django/fixtures.py b/pytest_django/fixtures.py
--- a/pytest_django/fixtures.py
+++ b/pytest_django/fixtures.py
@@ -3,6 +3,7 @@
 from __future__ import with_statement
 
 import os
+import warnings
 
 import pytest
 
@@ -288,11 +289,21 @@ def live_server(request):
           the other way around) transactional database access will be
           needed as data inside a transaction is not shared between
           the live server and test code.
+
+          Static assets will be served for all versions of Django.
+          Except for django >= 1.7, if ``django.contrib.staticfiles`` is not
+          installed.
     """
     skip_if_no_django()
     addr = request.config.getvalue('liveserver')
+    if not addr:
+        addr = os.getenv('DJANGO_LIVE_TEST_SERVER_ADDRESS')
     if not addr:
         addr = os.getenv('DJANGO_TEST_LIVE_SERVER_ADDRESS')
+        if addr:
+            warnings.warn('Please use DJANGO_LIVE_TEST_SERVER_ADDRESS'
+                          ' instead of DJANGO_TEST_LIVE_SERVER_ADDRESS.',
+                          DeprecationWarning)
     if not addr:
         addr = 'localhost:8081,8100-8200'
     server = live_server_helper.LiveServer(addr)
diff --git a/pytest_django/live_server_helper.py b/pytest_django/live_server_helper.py
--- a/pytest_django/live_server_helper.py
+++ b/pytest_django/live_server_helper.py
@@ -2,6 +2,8 @@
 
 import pytest
 
+from .lazy_django import get_django_version
+
 
 def supported():
     import django.test.testcases
@@ -35,11 +37,19 @@ def __init__(self, addr):
                 connections_override[conn.alias] = conn
 
         liveserver_kwargs = {'connections_override': connections_override}
-        try:
-            from django.test.testcases import _StaticFilesHandler
-            liveserver_kwargs['static_handler'] = _StaticFilesHandler
-        except ImportError:
-            pass
+        from django.conf import settings
+        if ('django.contrib.staticfiles' in settings.INSTALLED_APPS and
+                get_django_version() >= (1, 7)):
+            from django.contrib.staticfiles.handlers import (
+                StaticFilesHandler)
+            liveserver_kwargs['static_handler'] = StaticFilesHandler
+        else:
+            try:
+                from django.test.testcases import _StaticFilesHandler
+            except ImportError:
+                pass
+            else:
+                liveserver_kwargs['static_handler'] = _StaticFilesHandler
 
         host, possible_ports = parse_addr(addr)
         self.thread = LiveServerThread(host, possible_ports,


Test patch:
diff --git a/tests/app/static/a_file.txt b/tests/app/static/a_file.txt
new file mode 100644
--- /dev/null
+++ b/tests/app/static/a_file.txt
@@ -0,0 +1 @@
+bla
diff --git a/tests/compat.py b/tests/compat.py
--- a/tests/compat.py
+++ b/tests/compat.py
@@ -5,6 +5,6 @@
 
 
 try:
-    from urllib2 import urlopen  # noqa
+    from urllib2 import urlopen, HTTPError  # noqa
 except ImportError:
-    from urllib.request import urlopen  # noqa
+    from urllib.request import urlopen, HTTPError  # noqa
diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py
--- a/tests/test_fixtures.py
+++ b/tests/test_fixtures.py
@@ -12,7 +12,7 @@
 from django.test.testcases import connections_support_transactions
 
 from .app.models import Item
-from .compat import force_text, urlopen
+from .compat import force_text, urlopen, HTTPError
 from .test_database import noop_transactions
 
 from pytest_django.lazy_django import get_django_version
@@ -147,6 +147,74 @@ def test_item_transactional_db(self, item_transactional_db, live_server):
         response_data = urlopen(live_server + '/item_count/').read()
         assert force_text(response_data) == 'Item count: 1'
 
+    @pytest.mark.skipif(get_django_version() >= (1, 7),
+                        reason="Django < 1.7 required")
+    def test_serve_static(self, live_server, settings):
+        """
+        Test that the LiveServer serves static files by default.
+        """
+        response_data = urlopen(live_server + '/static/a_file.txt').read()
+        assert force_text(response_data) == 'bla\n'
+
+    @pytest.mark.django_project(extra_settings="""
+        import os
+
+        ROOT_URLCONF = 'tests.urls'
+        INSTALLED_APPS = [
+            'django.contrib.auth',
+            'django.contrib.contenttypes',
+            'django.contrib.sessions',
+            'django.contrib.sites',
+            'tests.app',
+        ]
+
+        STATIC_URL = '/static/'
+        SECRET_KEY = 'foobar'
+
+        SITE_ID = 1234  # Needed for 1.3 compatibility
+
+        # extra settings
+        INSTALLED_APPS += ['django.contrib.staticfiles',]
+        """)
+    def test_serve_static_with_staticfiles_app(self, django_testdir, settings):
+        """
+        LiveServer always serves statics with ``django.contrib.staticfiles``
+        handler.
+        """
+        django_testdir.create_test_module("""
+            import pytest
+            try:
+                from django.utils.encoding import force_text
+            except ImportError:
+                from django.utils.encoding import force_unicode as force_text
+
+            try:
+                from urllib2 import urlopen, HTTPError
+            except ImportError:
+                from urllib.request import urlopen, HTTPError
+
+            class TestLiveServer:
+                def test_a(self, live_server, settings):
+                    assert ('django.contrib.staticfiles'
+                            in settings.INSTALLED_APPS)
+                    response_data = urlopen(
+                        live_server + '/static/a_file.txt').read()
+                    assert force_text(response_data) == 'bla\\n'
+            """)
+        result = django_testdir.runpytest('--tb=short', '-v')
+        result.stdout.fnmatch_lines(['*test_a*PASSED*'])
+
+    @pytest.mark.skipif(get_django_version() < (1, 7),
+                        reason="Django >= 1.7 required")
+    def test_serve_static_dj17_without_staticfiles_app(self, live_server,
+                                                       settings):
+        """
+        Because ``django.contrib.staticfiles`` is not installed
+        LiveServer can not serve statics with django >= 1.7 .
+        """
+        with pytest.raises(HTTPError):
+            urlopen(live_server + '/static/a_file.txt').read()
+
 
 @pytest.mark.django_project(extra_settings="""
     AUTH_USER_MODEL = 'app.MyCustomUser'