mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-02-05 10:53:28 -05:00
Make URLs for assets cache-proof
https://www.pivotaltracker.com/story/show/113448149 This commit adds a query string to assets URLs which is generated from a hash of the file contents. When asset files are changed they will now be served from a different URL, which means they wont be loaded from browser cache. This is similar to how GOV.UK template adds its version number as a querystring parameter for its assets. This is mostly copied from Digital Marketplace utils: https://github.com/alphagov/digitalmarketplace-utils/pull/102 They have it in a shared codebase, we only have one frontend app so don’t need to do that. Usage in a template: ``` jinja {{ asset_fingerprinter.get_url('stylesheets/application.css') }} ``` Output: ``` static/stylesheets/application.css?418e6f4a6cdf1142e45c072ed3e1c90a ```
This commit is contained in:
95
tests/app/main/test_asset_fingerprinter.py
Normal file
95
tests/app/main/test_asset_fingerprinter.py
Normal file
@@ -0,0 +1,95 @@
|
||||
# coding=utf-8
|
||||
import os
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from app.asset_fingerprinter import AssetFingerprinter
|
||||
|
||||
|
||||
@mock.patch.object(AssetFingerprinter, 'get_asset_file_contents')
|
||||
class TestAssetFingerprint(object):
|
||||
def test_url_format(self, get_file_content_mock):
|
||||
get_file_content_mock.return_value = """
|
||||
body {
|
||||
font-family: nta;
|
||||
}
|
||||
"""
|
||||
asset_fingerprinter = AssetFingerprinter(
|
||||
asset_root='/suppliers/static/'
|
||||
)
|
||||
assert (
|
||||
asset_fingerprinter.get_url('application.css') ==
|
||||
'/suppliers/static/application.css?418e6f4a6cdf1142e45c072ed3e1c90a' # noqa
|
||||
)
|
||||
assert (
|
||||
asset_fingerprinter.get_url('application-ie6.css') ==
|
||||
'/suppliers/static/application-ie6.css?418e6f4a6cdf1142e45c072ed3e1c90a' # noqa
|
||||
)
|
||||
|
||||
def test_building_file_path(self, get_file_content_mock):
|
||||
get_file_content_mock.return_value = """
|
||||
document.write('Hello world!');
|
||||
"""
|
||||
fingerprinter = AssetFingerprinter()
|
||||
fingerprinter.get_url('javascripts/application.js')
|
||||
fingerprinter.get_asset_file_contents.assert_called_with(
|
||||
'app/static/javascripts/application.js'
|
||||
)
|
||||
|
||||
def test_hashes_are_consistent(self, get_file_content_mock):
|
||||
get_file_content_mock.return_value = """
|
||||
body {
|
||||
font-family: nta;
|
||||
}
|
||||
"""
|
||||
asset_fingerprinter = AssetFingerprinter()
|
||||
assert (
|
||||
asset_fingerprinter.get_asset_fingerprint('application.css') ==
|
||||
asset_fingerprinter.get_asset_fingerprint('same_contents.css')
|
||||
)
|
||||
|
||||
def test_hashes_are_different_for_different_files(
|
||||
self, get_file_content_mock
|
||||
):
|
||||
asset_fingerprinter = AssetFingerprinter()
|
||||
get_file_content_mock.return_value = """
|
||||
body {
|
||||
font-family: nta;
|
||||
}
|
||||
"""
|
||||
css_hash = asset_fingerprinter.get_asset_fingerprint('application.css')
|
||||
get_file_content_mock.return_value = """
|
||||
document.write('Hello world!');
|
||||
"""
|
||||
js_hash = asset_fingerprinter.get_asset_fingerprint('application.js')
|
||||
assert (
|
||||
js_hash != css_hash
|
||||
)
|
||||
|
||||
def test_hash_gets_cached(self, get_file_content_mock):
|
||||
get_file_content_mock.return_value = """
|
||||
body {
|
||||
font-family: nta;
|
||||
}
|
||||
"""
|
||||
fingerprinter = AssetFingerprinter()
|
||||
assert (
|
||||
fingerprinter.get_url('application.css') ==
|
||||
'/static/application.css?418e6f4a6cdf1142e45c072ed3e1c90a'
|
||||
)
|
||||
fingerprinter._cache[
|
||||
'application.css'
|
||||
] = 'a1a1a1'
|
||||
assert (
|
||||
fingerprinter.get_url('application.css') ==
|
||||
'a1a1a1'
|
||||
)
|
||||
fingerprinter.get_asset_file_contents.assert_called_once_with(
|
||||
'app/static/application.css'
|
||||
)
|
||||
|
||||
|
||||
class TestAssetFingerprintWithUnicode(object):
|
||||
def test_can_read_self(self):
|
||||
string_with_unicode_character = 'Ralph’s apostrophe'
|
||||
AssetFingerprinter(filesystem_path='tests/app/main/').get_url('test_asset_fingerprinter.py')
|
||||
Reference in New Issue
Block a user