File: test_django.py

package info (click to toggle)
django-assets 2.0-6
  • links: PTS, VCS
  • area: main
  • in suites: forky, trixie
  • size: 368 kB
  • sloc: python: 986; makefile: 129; sh: 6
file content (315 lines) | stat: -rw-r--r-- 11,452 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# -*- coding: utf-8 -*-
import pytest

from django.conf import settings
from django.contrib.staticfiles import finders
from django.template import Template, Context
from django_assets.loaders import DjangoLoader
from django_assets import Bundle, register as django_env_register
from django_assets.env import get_env
from django_assets.env import reset as django_env_reset
from webassets import six

from webassets.test import (
    TempDirHelper,
    TempEnvironmentHelper as BaseTempEnvironmentHelper,
)
from webassets.filter import get_filter
from webassets.exceptions import BundleError

from django_assets.templatetags.assets import AssetsNode


class TempEnvironmentHelper(BaseTempEnvironmentHelper):
    """Base-class for tests which will:

    - Reset the Django settings after each test.
    - Reset the django-assets environment after each test.
    - Initialize MEDIA_ROOT to point to a temporary directory.
    """

    def setup_method(self):
        TempDirHelper.setup(self)

        # Reset the webassets environment.
        django_env_reset()
        self.env = get_env()

        # Use a temporary directory as MEDIA_ROOT
        settings.MEDIA_ROOT = self.create_directories('media')[0]
        settings.STATIC_ROOT = None

        # Some other settings without which we are likely to run
        # into errors being raised as part of validation.
        setattr(settings, 'DATABASES', {})
        settings.DATABASES['default'] = {'ENGINE': ''}

        # Unless we explicitly test it, we don't want to use the cache during
        # testing.
        self.env.cache = False
        self.env.manifest = False

    def teardown_method(self):
        super(TempEnvironmentHelper, self).teardown()
        finders.get_finder.cache_clear()


class TestConfig(object):
    """The environment configuration is backed by the Django settings
    object.
    """

    def test_default_options(self):
        """The builtin options have different names within the Django
        settings, to make it obvious they belong to django-assets.
        """

        settings.ASSETS_URL_EXPIRE = True
        assert get_env().config['url_expire'] == settings.ASSETS_URL_EXPIRE

        settings.ASSETS_ROOT = 'FOO_ASSETS'
        settings.STATIC_ROOT = 'FOO_STATIC'
        settings.MEDIA_ROOT = 'FOO_MEDIA'
        # Pointing to ASSETS_ROOT
        assert get_env().directory.endswith('FOO_ASSETS')
        get_env().directory = 'BAR'
        assert settings.ASSETS_ROOT == 'BAR'
        # Pointing to STATIC_ROOT
        delattr(settings, 'ASSETS_ROOT')
        assert get_env().directory.endswith('FOO_STATIC')
        get_env().directory = 'BAR'
        assert settings.STATIC_ROOT == 'BAR'
        # Pointing to MEDIA_ROOT; Note we only
        # set STATIC_ROOT to None rather than deleting
        # it, a scenario that may occur in the wild.
        settings.STATIC_ROOT = None
        assert get_env().directory.endswith('FOO_MEDIA')
        get_env().directory = 'BAR'
        assert settings.MEDIA_ROOT == 'BAR'

    def test_custom_options(self):
        settings.FOO = 42
        assert get_env().config['foo'] == 42
        # Also, we are caseless.
        assert get_env().config['foO'] == 42


class TestTemplateTag():

    def setup_method(self):
        test_instance = self
        class MockBundle(Bundle):
            urls_to_fake = ['foo']
            def __init__(self, *a, **kw):
                Bundle.__init__(self, *a, **kw)
                # Kind of hacky, but gives us access to the last Bundle
                # instance used by our Django template tag.
                test_instance.the_bundle = self
            def _urls(self, *a, **kw):
                return self.urls_to_fake
        # Inject our mock bundle class
        self._old_bundle_class = AssetsNode.BundleClass
        AssetsNode.BundleClass = self.BundleClass = MockBundle

        # Reset the Django asset environment, init it with some
        # dummy bundles.
        django_env_reset()
        self.foo_bundle = Bundle()
        self.bar_bundle = Bundle()
        django_env_register('foo_bundle', self.foo_bundle)
        django_env_register('bar_bundle', self.bar_bundle)

    def teardown_method(self):
        AssetsNode.BundleClass = self._old_bundle_class
        del self._old_bundle_class

    def render_template(self, args, ctx={}):
        return Template('{% load assets %}{% assets '+args+' %}{{ ASSET_URL }};{% endassets %}').render(Context(ctx))

    def test_reference_bundles(self):
        self.render_template('"foo_bundle", "bar_bundle"')
        assert self.the_bundle.contents == (self.foo_bundle, self.bar_bundle)

    def test_reference_files(self):
        self.render_template('"file1", "file2", "file3"')
        assert self.the_bundle.contents == ('file1', 'file2', 'file3',)

    def test_reference_mixed(self):
        self.render_template('"foo_bundle", "file2", "file3"')
        assert self.the_bundle.contents == (self.foo_bundle, 'file2', 'file3',)

    def test_with_vars(self):
        self.render_template('var1 var2', {'var1': self.foo_bundle, 'var2': 'a_file'})
        assert self.the_bundle.contents == (self.foo_bundle, 'a_file',)

    def test_debug_option(self):
        self.render_template('"file", debug="true"')
        assert self.the_bundle.debug == True
        self.render_template('"file", debug="false"')
        assert self.the_bundle.debug == False
        self.render_template('"file", debug="merge"')
        assert self.the_bundle.debug == "merge"

    def test_with_no_commas(self):
        """Using commas is optional.
        """
        self.render_template('"file1" "file2" "file3"')

    def test_output_urls(self):
        """Ensure the tag correcly spits out the urls the bundle returns.
        """
        self.BundleClass.urls_to_fake = ['foo', 'bar']
        assert self.render_template('"file1" "file2" "file3"') == 'foo;bar;'


class TestLoader(TempDirHelper):

    default_files = {
        'template.html': """
            {% load assets %}
            <h1>Test</h1>
            {% if foo %}
                {% assets "A" "B" "C" output="output.html" %}
                    {{ ASSET_URL }}
                {% endassets %}
            {% endif %}
            """
    }

    def setup_method(self):
        TempDirHelper.setup(self)

        self.loader = DjangoLoader()
        settings.TEMPLATES[0]['OPTIONS'] = {
            'loaders': (
                'django.template.loaders.filesystem.Loader'
            ),
        }
        settings.TEMPLATES[0]['DIRS'] = [self.tempdir]

    def test(self):
        bundles = self.loader.load_bundles()
        assert len(bundles) == 1
        assert bundles[0].output == "output.html"

    def test_cached_loader(self):
        settings.TEMPLATE_LOADERS = (
            ('django.template.loaders.cached.Loader', (
                'django.template.loaders.filesystem.Loader',
                )),
            )
        bundles = self.loader.load_bundles()
        assert len(bundles) == 1
        assert bundles[0].output == "output.html"


class TestStaticFiles(TempEnvironmentHelper):
    """Test integration with django.contrib.staticfiles.
    """

    def setup_method(self):
        try:
            import django.contrib.staticfiles
        except ImportError:
            raise SkipTest()

        TempEnvironmentHelper.setup_method(self)

        # Configure a staticfiles-using project.
        settings.STATIC_ROOT = settings.MEDIA_ROOT   # /media via baseclass
        settings.MEDIA_ROOT = self.path('needs_to_differ_from_static_root')
        settings.STATIC_URL = '/media/'
        settings.INSTALLED_APPS += ('django.contrib.staticfiles',)
        settings.STATICFILES_DIRS = tuple(self.create_directories('foo', 'bar'))
        if 'django_assets.finders.AssetsFinder' not in settings.STATICFILES_FINDERS:
            settings.STATICFILES_FINDERS += ('django_assets.finders.AssetsFinder',)
        self.create_files({'foo/file1': 'foo', 'bar/file2': 'bar'})
        settings.ASSETS_DEBUG = True

    def test_build(self):
        """Finders are used to find source files.
        """
        self.mkbundle('file1', 'file2', output="out").build()
        assert self.get("media/out") == "foo\nbar"

    def test_build_nodebug(self):
        """If debug is disabled, the finders are not used.
        """
        settings.ASSETS_DEBUG = False
        bundle = self.mkbundle('file1', 'file2', output="out")
        pytest.raises(BundleError, bundle.build)

        # After creating the files in the static root directory,
        # it works (we only look there in production).
        from django.core.management import call_command
        call_command("collectstatic", interactive=False)

        bundle.build()
        assert self.get("media/out") == "foo\nbar"

    def test_find_with_glob(self):
        """Globs can be used across staticdirs."""
        self.mkbundle('file?', output="out").build()
        assert self.get("media/out") == "foo\nbar"

    def test_find_with_recursive_glob(self):
        """Recursive globs."""
        self.create_files({'foo/subdir/foundit.js': '42'})
        self.mkbundle('**/*.js', output="out").build()
        assert self.get("media/out") == "42"

    def test_missing_file(self):
        """An error is raised if a source file is missing.
        """
        bundle = self.mkbundle('xyz', output="out")
        pytest.raises(BundleError, bundle.build)

    def test_serve_built_files(self):
        """The files we write to STATIC_ROOT are served in debug mode
        using "django_assets.finders.AssetsFinder".
        """
        self.mkbundle('file1', 'file2', output="out").build()
        # I tried using the test client for this, but it would
        # need to be setup using StaticFilesHandler, which is
        # incompatible with the test client.
        from django_assets.finders import AssetsFinder
        assert AssetsFinder().find('out') == self.path("media/out")

    def test_css_rewrite(self):
        """Test that the cssrewrite filter can deal with staticfiles.
        """
        # file1 is in ./foo, file2 is in ./bar, the output will be
        # STATIC_ROOT = ./media
        self.create_files(
                {'foo/css': 'h1{background: url("file1"), url("file2")}'})
        self.mkbundle('css', filters='cssrewrite', output="out").build()
        # The urls are NOT rewritte to foo/file1, but because all three
        # directories are essentially mapped into the same url space, they
        # remain as is.
        assert self.get('media/out') == \
                '''h1{background: url("file1"), url("file2")}'''


class TestFilter(TempEnvironmentHelper):
    def get(self, name):
        """Return the given file's contents.
        """
        if not six.PY3:
            return super(TestFilter, self).get(name).decode('utf-8')

        import codecs
        with codecs.open(self.path(name), "r", "utf-8") as f:
            return f.read()

    def test_template(self):
        self.create_files({
            'media/foo.html': 'Ünicôdé-Chèck: {{ num|filesizeformat }}',
        })
        self.mkbundle(
            'foo.html',
            output="out",
            filters=get_filter('template', context={'num': 23232323}),
        ).build()

        # Depending on Django version "filesizeformat" may contain a breaking space
        assert self.get('media/out') in ('Ünicôdé-Chèck: 22.2\xa0MB', 'Ünicôdé-Chèck: 22.2 MB')