Compare commits
7 Commits
0f19fcb174
...
b3dfab2611
Author | SHA1 | Date |
---|---|---|
Brian S. Stephan | b3dfab2611 | |
Brian S. Stephan | 715bc38d78 | |
Brian S. Stephan | e9af2de21e | |
Brian S. Stephan | 83bc8b2c21 | |
Brian S. Stephan | 4a2f650a33 | |
Brian S. Stephan | fd0fb390ff | |
Brian S. Stephan | be8a8dd35a |
|
@ -40,8 +40,9 @@ def create_app(instance_path=None, test_config=None):
|
||||||
logger.info("RESPONSE: %s %s: %s", request.method, request.path, response.status)
|
logger.info("RESPONSE: %s %s: %s", request.method, request.path, response.status)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
from . import error_pages, pages
|
from . import error_pages, pages, static
|
||||||
app.register_blueprint(pages.bp)
|
app.register_blueprint(pages.bp)
|
||||||
|
app.register_blueprint(static.bp)
|
||||||
app.register_error_handler(400, error_pages.bad_request)
|
app.register_error_handler(400, error_pages.bad_request)
|
||||||
app.register_error_handler(404, error_pages.page_not_found)
|
app.register_error_handler(404, error_pages.page_not_found)
|
||||||
app.register_error_handler(500, error_pages.internal_server_error)
|
app.register_error_handler(500, error_pages.internal_server_error)
|
||||||
|
|
|
@ -50,6 +50,12 @@ class Config(object):
|
||||||
MEDIA_DIR = 'media'
|
MEDIA_DIR = 'media'
|
||||||
|
|
||||||
# customizations
|
# customizations
|
||||||
|
PAGE_STYLES = {
|
||||||
|
'dark': '/static/css/dark.css',
|
||||||
|
'light': '/static/css/light.css',
|
||||||
|
'plain': '/static/css/plain.css',
|
||||||
|
}
|
||||||
|
|
||||||
DEFAULT_PAGE_STYLE = 'light'
|
DEFAULT_PAGE_STYLE = 'light'
|
||||||
TITLE_SUFFIX = 'example.com'
|
TITLE_SUFFIX = 'example.com'
|
||||||
CONTACT_EMAIL = 'admin@example.com'
|
CONTACT_EMAIL = 'admin@example.com'
|
||||||
|
|
|
@ -31,19 +31,15 @@ def render(template_name_or_list, **context):
|
||||||
|
|
||||||
* Determine the proper site theme to use in the template and provide it.
|
* Determine the proper site theme to use in the template and provide it.
|
||||||
"""
|
"""
|
||||||
PAGE_STYLES = {
|
page_styles = app.config['PAGE_STYLES']
|
||||||
'dark': 'css/dark.css',
|
|
||||||
'light': 'css/light.css',
|
|
||||||
'plain': 'css/plain.css',
|
|
||||||
}
|
|
||||||
|
|
||||||
selected_style = request.args.get('style', None)
|
selected_style = request.args.get('style', None)
|
||||||
if selected_style:
|
if selected_style:
|
||||||
user_style = selected_style
|
user_style = selected_style
|
||||||
else:
|
else:
|
||||||
user_style = request.cookies.get('user-style')
|
user_style = request.cookies.get('user-style')
|
||||||
logger.debug("user style cookie: %s", user_style)
|
logger.debug("user style cookie: %s", user_style)
|
||||||
context['user_style'] = PAGE_STYLES.get(user_style, PAGE_STYLES.get(app.config['DEFAULT_PAGE_STYLE']))
|
context['user_style'] = page_styles.get(user_style, page_styles.get(app.config['DEFAULT_PAGE_STYLE']))
|
||||||
|
context['page_styles'] = page_styles
|
||||||
|
|
||||||
resp = make_response(render_template(template_name_or_list, **context))
|
resp = make_response(render_template(template_name_or_list, **context))
|
||||||
if selected_style:
|
if selected_style:
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
"""Serve static files from the instance directory."""
|
||||||
|
import os
|
||||||
|
|
||||||
|
from flask import Blueprint
|
||||||
|
from flask import current_app as app
|
||||||
|
from flask import send_from_directory
|
||||||
|
|
||||||
|
bp = Blueprint('static', __name__, url_prefix='/custom-static')
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/<path:name>')
|
||||||
|
def serve_instance_static_file(name):
|
||||||
|
"""Serve a static file from the instance directory, used for customization."""
|
||||||
|
return send_from_directory(os.path.join(app.instance_path, 'custom-static'), name)
|
|
@ -28,7 +28,8 @@ body {
|
||||||
|
|
||||||
a {
|
a {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-decoration: none;
|
text-decoration-line: underline;
|
||||||
|
text-decoration-thickness: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.header {
|
div.header {
|
||||||
|
@ -39,10 +40,6 @@ div.header {
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.header a {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.content {
|
div.content {
|
||||||
font-size: 11pt;
|
font-size: 11pt;
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
|
@ -170,6 +167,5 @@ figcaption {
|
||||||
}
|
}
|
||||||
|
|
||||||
.footnote-ref:link, .footnote-ref:visited, .footnote-ref:hover, .footnote-ref:active {
|
.footnote-ref:link, .footnote-ref:visited, .footnote-ref:hover, .footnote-ref:active {
|
||||||
border-bottom: none;
|
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,17 +15,14 @@ h1, h2, h3, h4, h5, h6 {
|
||||||
|
|
||||||
p a, ul a, ol a {
|
p a, ul a, ol a {
|
||||||
color: #DDD;
|
color: #DDD;
|
||||||
border-bottom: 1px solid #DDD;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
footer a {
|
footer a {
|
||||||
color: #999;
|
color: #999;
|
||||||
border-bottom: 1px solid #999;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p a:hover, ul a:hover, ol a:hover, footer a:hover {
|
p a:hover, ul a:hover, ol a:hover, footer a:hover {
|
||||||
color: #B31D15;
|
color: #B31D15;
|
||||||
border-bottom: 1px solid #B31D15;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
div.site-wrap {
|
div.site-wrap {
|
||||||
|
@ -34,10 +31,7 @@ div.site-wrap {
|
||||||
|
|
||||||
div.header, div.header a {
|
div.header, div.header a {
|
||||||
color: #555;
|
color: #555;
|
||||||
}
|
text-decoration: none;
|
||||||
|
|
||||||
div.header a:hover, div.header a:active {
|
|
||||||
border-bottom: 1px solid #555;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
table, th, td {
|
table, th, td {
|
||||||
|
|
|
@ -15,17 +15,14 @@ h1, h2, h3, h4, h5, h6 {
|
||||||
|
|
||||||
p a, ul a, ol a {
|
p a, ul a, ol a {
|
||||||
color: #222;
|
color: #222;
|
||||||
border-bottom: 1px solid #222;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
footer a {
|
footer a {
|
||||||
color: #999;
|
color: #999;
|
||||||
border-bottom: 1px solid #999;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p a:hover, ul a:hover, ol a:hover, footer a:hover {
|
p a:hover, ul a:hover, ol a:hover, footer a:hover {
|
||||||
color: #811610;
|
color: #811610;
|
||||||
border-bottom: 1px solid #811610;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
div.site-wrap {
|
div.site-wrap {
|
||||||
|
@ -34,10 +31,7 @@ div.site-wrap {
|
||||||
|
|
||||||
div.header, div.header a {
|
div.header, div.header a {
|
||||||
color: #AAA;
|
color: #AAA;
|
||||||
}
|
text-decoration: none;
|
||||||
|
|
||||||
div.header a:hover, div.header a:active {
|
|
||||||
border-bottom: 1px solid #AAA;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
table, th, td {
|
table, th, td {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<meta property="og:url" content="{{ base_url }}">
|
<meta property="og:url" content="{{ base_url }}">
|
||||||
<meta name="twitter:card" content="summary_large_image">
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename=user_style) }}">
|
<link rel="stylesheet" href="{{ user_style }}">
|
||||||
<link rel="icon" href="{% if config.FAVICON %}{{ config.FAVICON }}{% else %}{{ url_for('static', filename='img/favicon.png') }}{% endif %}">
|
<link rel="icon" href="{% if config.FAVICON %}{{ config.FAVICON }}{% else %}{{ url_for('static', filename='img/favicon.png') }}{% endif %}">
|
||||||
|
|
||||||
<div {% block site_class %}class="site-wrap site-wrap-normal-width"{% endblock %}>
|
<div {% block site_class %}class="site-wrap site-wrap-normal-width"{% endblock %}>
|
||||||
|
@ -20,9 +20,9 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<div class="styles">
|
<div class="styles">
|
||||||
<a href="?style=dark">[dark]</a>
|
{% for style in page_styles %}
|
||||||
<a href="?style=light">[light]</a>
|
<a href="?style={{ style }}">[{{ style }}]</a>
|
||||||
<a href="?style=plain">[plain]</a>
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -21,6 +21,6 @@ safety # check requirements file for issues
|
||||||
|
|
||||||
# maintenance utilities and tox
|
# maintenance utilities and tox
|
||||||
pip-tools # pip-compile
|
pip-tools # pip-compile
|
||||||
tox # CI stuff
|
tox<4 # CI stuff, pinned for now to avoid packaging conflict w/safety
|
||||||
tox-wheel # build wheels in tox
|
tox-wheel # build wheels in tox
|
||||||
versioneer # automatic version numbering
|
versioneer # automatic version numbering
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
#
|
#
|
||||||
# This file is autogenerated by pip-compile with python 3.10
|
# This file is autogenerated by pip-compile with Python 3.10
|
||||||
# To update, run:
|
# by the following command:
|
||||||
#
|
#
|
||||||
# pip-compile --output-file=requirements/requirements-dev.txt requirements/requirements-dev.in
|
# pip-compile --output-file=requirements/requirements-dev.txt requirements/requirements-dev.in
|
||||||
#
|
#
|
||||||
attrs==22.1.0
|
attrs==22.2.0
|
||||||
# via pytest
|
# via pytest
|
||||||
bandit==1.7.4
|
bandit==1.7.4
|
||||||
# via -r requirements/requirements-dev.in
|
# via -r requirements/requirements-dev.in
|
||||||
build==0.8.0
|
build==0.9.0
|
||||||
# via pip-tools
|
# via pip-tools
|
||||||
certifi==2022.9.14
|
certifi==2022.12.7
|
||||||
# via requests
|
# via requests
|
||||||
charset-normalizer==2.1.1
|
charset-normalizer==2.1.1
|
||||||
# via requests
|
# via requests
|
||||||
|
@ -19,15 +19,17 @@ click==8.1.3
|
||||||
# flask
|
# flask
|
||||||
# pip-tools
|
# pip-tools
|
||||||
# safety
|
# safety
|
||||||
coverage[toml]==6.4.4
|
coverage[toml]==7.0.1
|
||||||
# via pytest-cov
|
# via pytest-cov
|
||||||
distlib==0.3.6
|
distlib==0.3.6
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
dlint==0.13.0
|
dlint==0.13.0
|
||||||
# via -r requirements/requirements-dev.in
|
# via -r requirements/requirements-dev.in
|
||||||
dparse==0.6.0
|
dparse==0.6.2
|
||||||
# via safety
|
# via safety
|
||||||
filelock==3.8.0
|
exceptiongroup==1.1.0
|
||||||
|
# via pytest
|
||||||
|
filelock==3.9.0
|
||||||
# via
|
# via
|
||||||
# tox
|
# tox
|
||||||
# virtualenv
|
# virtualenv
|
||||||
|
@ -42,31 +44,31 @@ flake8==5.0.4
|
||||||
# flake8-mutable
|
# flake8-mutable
|
||||||
flake8-blind-except==0.2.1
|
flake8-blind-except==0.2.1
|
||||||
# via -r requirements/requirements-dev.in
|
# via -r requirements/requirements-dev.in
|
||||||
flake8-builtins==1.5.3
|
flake8-builtins==2.1.0
|
||||||
# via -r requirements/requirements-dev.in
|
# via -r requirements/requirements-dev.in
|
||||||
flake8-docstrings==1.6.0
|
flake8-docstrings==1.6.0
|
||||||
# via -r requirements/requirements-dev.in
|
# via -r requirements/requirements-dev.in
|
||||||
flake8-executable==2.1.1
|
flake8-executable==2.1.2
|
||||||
# via -r requirements/requirements-dev.in
|
# via -r requirements/requirements-dev.in
|
||||||
flake8-fixme==1.1.1
|
flake8-fixme==1.1.1
|
||||||
# via -r requirements/requirements-dev.in
|
# via -r requirements/requirements-dev.in
|
||||||
flake8-isort==4.2.0
|
flake8-isort==6.0.0
|
||||||
# via -r requirements/requirements-dev.in
|
# via -r requirements/requirements-dev.in
|
||||||
flake8-logging-format==0.7.5
|
flake8-logging-format==0.9.0
|
||||||
# via -r requirements/requirements-dev.in
|
# via -r requirements/requirements-dev.in
|
||||||
flake8-mutable==1.2.0
|
flake8-mutable==1.2.0
|
||||||
# via -r requirements/requirements-dev.in
|
# via -r requirements/requirements-dev.in
|
||||||
flask==2.2.2
|
flask==2.2.2
|
||||||
# via -r requirements/requirements.in
|
# via -r requirements/requirements.in
|
||||||
gitdb==4.0.9
|
gitdb==4.0.10
|
||||||
# via gitpython
|
# via gitpython
|
||||||
gitpython==3.1.27
|
gitpython==3.1.30
|
||||||
# via bandit
|
# via bandit
|
||||||
idna==3.4
|
idna==3.4
|
||||||
# via requests
|
# via requests
|
||||||
iniconfig==1.1.1
|
iniconfig==1.1.1
|
||||||
# via pytest
|
# via pytest
|
||||||
isort==5.10.1
|
isort==5.11.4
|
||||||
# via flake8-isort
|
# via flake8-isort
|
||||||
itsdangerous==2.1.2
|
itsdangerous==2.1.2
|
||||||
# via flask
|
# via flask
|
||||||
|
@ -87,22 +89,20 @@ packaging==21.3
|
||||||
# pytest
|
# pytest
|
||||||
# safety
|
# safety
|
||||||
# tox
|
# tox
|
||||||
pbr==5.10.0
|
pbr==5.11.0
|
||||||
# via stevedore
|
# via stevedore
|
||||||
pep517==0.13.0
|
pep517==0.13.0
|
||||||
# via build
|
# via build
|
||||||
pip-tools==6.8.0
|
pip-tools==6.12.1
|
||||||
# via -r requirements/requirements-dev.in
|
# via -r requirements/requirements-dev.in
|
||||||
platformdirs==2.5.2
|
platformdirs==2.6.2
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
pluggy==1.0.0
|
pluggy==1.0.0
|
||||||
# via
|
# via
|
||||||
# pytest
|
# pytest
|
||||||
# tox
|
# tox
|
||||||
py==1.11.0
|
py==1.11.0
|
||||||
# via
|
# via tox
|
||||||
# pytest
|
|
||||||
# tox
|
|
||||||
pycodestyle==2.9.1
|
pycodestyle==2.9.1
|
||||||
# via flake8
|
# via flake8
|
||||||
pydocstyle==6.1.1
|
pydocstyle==6.1.1
|
||||||
|
@ -115,11 +115,11 @@ pyparsing==3.0.9
|
||||||
# via
|
# via
|
||||||
# packaging
|
# packaging
|
||||||
# pydot
|
# pydot
|
||||||
pytest==7.1.3
|
pytest==7.2.0
|
||||||
# via
|
# via
|
||||||
# -r requirements/requirements-dev.in
|
# -r requirements/requirements-dev.in
|
||||||
# pytest-cov
|
# pytest-cov
|
||||||
pytest-cov==3.0.0
|
pytest-cov==4.0.0
|
||||||
# via -r requirements/requirements-dev.in
|
# via -r requirements/requirements-dev.in
|
||||||
pyyaml==6.0
|
pyyaml==6.0
|
||||||
# via bandit
|
# via bandit
|
||||||
|
@ -127,9 +127,9 @@ requests==2.28.1
|
||||||
# via safety
|
# via safety
|
||||||
ruamel-yaml==0.17.21
|
ruamel-yaml==0.17.21
|
||||||
# via safety
|
# via safety
|
||||||
ruamel-yaml-clib==0.2.6
|
ruamel-yaml-clib==0.2.7
|
||||||
# via ruamel-yaml
|
# via ruamel-yaml
|
||||||
safety==2.1.1
|
safety==2.3.5
|
||||||
# via -r requirements/requirements-dev.in
|
# via -r requirements/requirements-dev.in
|
||||||
six==1.16.0
|
six==1.16.0
|
||||||
# via tox
|
# via tox
|
||||||
|
@ -137,7 +137,7 @@ smmap==5.0.0
|
||||||
# via gitdb
|
# via gitdb
|
||||||
snowballstemmer==2.2.0
|
snowballstemmer==2.2.0
|
||||||
# via pydocstyle
|
# via pydocstyle
|
||||||
stevedore==4.0.0
|
stevedore==4.1.1
|
||||||
# via bandit
|
# via bandit
|
||||||
toml==0.10.2
|
toml==0.10.2
|
||||||
# via dparse
|
# via dparse
|
||||||
|
@ -148,21 +148,21 @@ tomli==2.0.1
|
||||||
# pep517
|
# pep517
|
||||||
# pytest
|
# pytest
|
||||||
# tox
|
# tox
|
||||||
tox==3.26.0
|
tox==3.28.0
|
||||||
# via
|
# via
|
||||||
# -r requirements/requirements-dev.in
|
# -r requirements/requirements-dev.in
|
||||||
# tox-wheel
|
# tox-wheel
|
||||||
tox-wheel==0.7.0
|
tox-wheel==1.0.0
|
||||||
# via -r requirements/requirements-dev.in
|
# via -r requirements/requirements-dev.in
|
||||||
urllib3==1.26.12
|
urllib3==1.26.13
|
||||||
# via requests
|
# via requests
|
||||||
versioneer==0.26
|
versioneer==0.28
|
||||||
# via -r requirements/requirements-dev.in
|
# via -r requirements/requirements-dev.in
|
||||||
virtualenv==20.16.5
|
virtualenv==20.17.1
|
||||||
# via tox
|
# via tox
|
||||||
werkzeug==2.2.2
|
werkzeug==2.2.2
|
||||||
# via flask
|
# via flask
|
||||||
wheel==0.37.1
|
wheel==0.38.4
|
||||||
# via
|
# via
|
||||||
# pip-tools
|
# pip-tools
|
||||||
# tox-wheel
|
# tox-wheel
|
||||||
|
|
|
@ -190,15 +190,15 @@ def test_setting_selected_style_includes_cookie(client):
|
||||||
response = client.get('/?style=light')
|
response = client.get('/?style=light')
|
||||||
style_cookie = next((cookie for cookie in client.cookie_jar if cookie.name == 'user-style'), None)
|
style_cookie = next((cookie for cookie in client.cookie_jar if cookie.name == 'user-style'), None)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert b'light.css' in response.data
|
assert b'/static/css/light.css' in response.data
|
||||||
assert b'dark.css' not in response.data
|
assert b'/static/css/dark.css' not in response.data
|
||||||
assert style_cookie.value == 'light'
|
assert style_cookie.value == 'light'
|
||||||
|
|
||||||
response = client.get('/?style=dark')
|
response = client.get('/?style=dark')
|
||||||
style_cookie = next((cookie for cookie in client.cookie_jar if cookie.name == 'user-style'), None)
|
style_cookie = next((cookie for cookie in client.cookie_jar if cookie.name == 'user-style'), None)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert b'dark.css' in response.data
|
assert b'/static/css/dark.css' in response.data
|
||||||
assert b'light.css' not in response.data
|
assert b'/static/css/light.css' not in response.data
|
||||||
assert style_cookie.value == 'dark'
|
assert style_cookie.value == 'dark'
|
||||||
|
|
||||||
|
|
||||||
|
@ -218,3 +218,23 @@ def test_extra_footer_per_page(client):
|
||||||
assert b'<div class="extra-footer">' not in response.data
|
assert b'<div class="extra-footer">' not in response.data
|
||||||
response = client.get('/index-but-with-footer')
|
response = client.get('/index-but-with-footer')
|
||||||
assert b'<div class="extra-footer"><i>ooo <a href="a">a</a></i>' in response.data
|
assert b'<div class="extra-footer"><i>ooo <a href="a">a</a></i>' in response.data
|
||||||
|
|
||||||
|
|
||||||
|
def test_serving_static_files(client):
|
||||||
|
"""Test the usage of send_from_directory to serve extra static files."""
|
||||||
|
response = client.get('/custom-static/css/warm.css')
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
# can't serve directories, just files
|
||||||
|
response = client.get('/custom-static/')
|
||||||
|
assert response.status_code == 404
|
||||||
|
response = client.get('/custom-static/css/')
|
||||||
|
assert response.status_code == 404
|
||||||
|
response = client.get('/custom-static/css')
|
||||||
|
assert response.status_code == 404
|
||||||
|
|
||||||
|
# can't serve files that don't exist or bad paths
|
||||||
|
response = client.get('/custom-static/css/cold.css')
|
||||||
|
assert response.status_code == 404
|
||||||
|
response = client.get('/custom-static/css/../../unreachable.md')
|
||||||
|
assert response.status_code == 404
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
* {
|
||||||
|
color: red;
|
||||||
|
}
|
|
@ -1,10 +1,15 @@
|
||||||
"""Unit test helper methods."""
|
"""Unit test helper methods."""
|
||||||
|
import os
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from werkzeug.http import dump_cookie
|
from werkzeug.http import dump_cookie
|
||||||
|
|
||||||
|
from incorporealcms import create_app
|
||||||
from incorporealcms.pages import (generate_parent_navs, instance_resource_path_to_request_path, render,
|
from incorporealcms.pages import (generate_parent_navs, instance_resource_path_to_request_path, render,
|
||||||
request_path_to_breadcrumb_display, request_path_to_instance_resource_path)
|
request_path_to_breadcrumb_display, request_path_to_instance_resource_path)
|
||||||
|
|
||||||
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
|
|
||||||
def test_generate_page_navs_index(app):
|
def test_generate_page_navs_index(app):
|
||||||
"""Test that the index page has navs to the root (itself)."""
|
"""Test that the index page has navs to the root (itself)."""
|
||||||
|
@ -49,22 +54,74 @@ def test_render_with_user_dark_theme(app):
|
||||||
"""Test that a request with the dark theme selected renders the dark theme."""
|
"""Test that a request with the dark theme selected renders the dark theme."""
|
||||||
cookie = dump_cookie("user-style", 'dark')
|
cookie = dump_cookie("user-style", 'dark')
|
||||||
with app.test_request_context(headers={'COOKIE': cookie}):
|
with app.test_request_context(headers={'COOKIE': cookie}):
|
||||||
assert b'dark.css' in render('base.html').data
|
assert b'/static/css/dark.css' in render('base.html').data
|
||||||
assert b'light.css' not in render('base.html').data
|
assert b'/static/css/light.css' not in render('base.html').data
|
||||||
|
|
||||||
|
|
||||||
def test_render_with_user_light_theme(app):
|
def test_render_with_user_light_theme(app):
|
||||||
"""Test that a request with the light theme selected renders the light theme."""
|
"""Test that a request with the light theme selected renders the light theme."""
|
||||||
with app.test_request_context():
|
with app.test_request_context():
|
||||||
assert b'light.css' in render('base.html').data
|
assert b'/static/css/light.css' in render('base.html').data
|
||||||
assert b'dark.css' not in render('base.html').data
|
assert b'/static/css/dark.css' not in render('base.html').data
|
||||||
|
|
||||||
|
|
||||||
def test_render_with_no_user_theme(app):
|
def test_render_with_no_user_theme(app):
|
||||||
"""Test that a request with no theme set renders the light theme."""
|
"""Test that a request with no theme set renders the light theme."""
|
||||||
with app.test_request_context():
|
with app.test_request_context():
|
||||||
assert b'light.css' in render('base.html').data
|
assert b'/static/css/light.css' in render('base.html').data
|
||||||
assert b'dark.css' not in render('base.html').data
|
assert b'/static/css/dark.css' not in render('base.html').data
|
||||||
|
|
||||||
|
|
||||||
|
def test_render_with_theme_defaults_affects_html(app):
|
||||||
|
"""Test that the base themes are all that's presented in the HTML."""
|
||||||
|
# test we can remove stuff from the default
|
||||||
|
with app.test_request_context():
|
||||||
|
assert b'?style=light' in render('base.html').data
|
||||||
|
assert b'?style=dark' in render('base.html').data
|
||||||
|
assert b'?style=plain' in render('base.html').data
|
||||||
|
|
||||||
|
|
||||||
|
def test_render_with_theme_overrides_affects_html(app):
|
||||||
|
"""Test that the overridden themes are presented in the HTML."""
|
||||||
|
# test we can remove stuff from the default
|
||||||
|
restyled_app = create_app(instance_path=os.path.join(HERE, 'instance'),
|
||||||
|
test_config={'PAGE_STYLES': {'light': '/static/css/light.css'}})
|
||||||
|
with restyled_app.test_request_context():
|
||||||
|
assert b'?style=light' in render('base.html').data
|
||||||
|
assert b'?style=dark' not in render('base.html').data
|
||||||
|
assert b'?style=plain' not in render('base.html').data
|
||||||
|
|
||||||
|
# test that we can add new stuff too/instead
|
||||||
|
restyled_app = create_app(instance_path=os.path.join(HERE, 'instance'),
|
||||||
|
test_config={'PAGE_STYLES': {'cool': '/static/css/cool.css',
|
||||||
|
'warm': '/static/css/warm.css'},
|
||||||
|
'DEFAULT_PAGE_STYLE': 'warm'})
|
||||||
|
with restyled_app.test_request_context():
|
||||||
|
assert b'?style=cool' in render('base.html').data
|
||||||
|
assert b'?style=warm' in render('base.html').data
|
||||||
|
|
||||||
|
|
||||||
|
def test_render_with_theme_overrides(app):
|
||||||
|
"""Test that the loaded themes can be overridden from the default."""
|
||||||
|
cookie = dump_cookie("user-style", 'cool')
|
||||||
|
restyled_app = create_app(instance_path=os.path.join(HERE, 'instance'),
|
||||||
|
test_config={'PAGE_STYLES': {'cool': '/static/css/cool.css',
|
||||||
|
'warm': '/static/css/warm.css'}})
|
||||||
|
with restyled_app.test_request_context(headers={'COOKIE': cookie}):
|
||||||
|
assert b'/static/css/cool.css' in render('base.html').data
|
||||||
|
assert b'/static/css/warm.css' not in render('base.html').data
|
||||||
|
|
||||||
|
|
||||||
|
def test_render_with_theme_overrides_not_found_is_default(app):
|
||||||
|
"""Test that theme overrides work, and if a requested theme doesn't exist, the default is loaded."""
|
||||||
|
cookie = dump_cookie("user-style", 'nonexistent')
|
||||||
|
restyled_app = create_app(instance_path=os.path.join(HERE, 'instance'),
|
||||||
|
test_config={'PAGE_STYLES': {'cool': '/static/css/cool.css',
|
||||||
|
'warm': '/static/css/warm.css'},
|
||||||
|
'DEFAULT_PAGE_STYLE': 'warm'})
|
||||||
|
with restyled_app.test_request_context(headers={'COOKIE': cookie}):
|
||||||
|
assert b'/static/css/warm.css' in render('base.html').data
|
||||||
|
assert b'/static/css/nonexistent.css' not in render('base.html').data
|
||||||
|
|
||||||
|
|
||||||
def test_request_path_to_instance_resource_path(app):
|
def test_request_path_to_instance_resource_path(app):
|
||||||
|
|
3
tox.ini
3
tox.ini
|
@ -56,9 +56,10 @@ commands =
|
||||||
# run security checks
|
# run security checks
|
||||||
#
|
#
|
||||||
# again it seems the most valuable here to run against the packaged code
|
# again it seems the most valuable here to run against the packaged code
|
||||||
|
# 51457 is nearly a red herring that I'm stuck with because tox is pinned, try removing occasionally
|
||||||
commands =
|
commands =
|
||||||
bandit {envsitepackagesdir}/incorporealcms/ -r
|
bandit {envsitepackagesdir}/incorporealcms/ -r
|
||||||
safety check -r requirements/requirements-dev.txt
|
safety check -r requirements/requirements-dev.txt -i 51457
|
||||||
|
|
||||||
[testenv:lint]
|
[testenv:lint]
|
||||||
# run style checks
|
# run style checks
|
||||||
|
|
Loading…
Reference in New Issue