92 lines
3.8 KiB
Python
92 lines
3.8 KiB
Python
|
|
"""Render real workflow templates to verify permissions and common page structure."""
|
||
|
|
from html.parser import HTMLParser
|
||
|
|
from types import SimpleNamespace
|
||
|
|
from jinja2 import ChoiceLoader, DictLoader, Environment, FileSystemLoader
|
||
|
|
|
||
|
|
|
||
|
|
class Elements(HTMLParser):
|
||
|
|
def __init__(self, html):
|
||
|
|
super().__init__()
|
||
|
|
self.ids = {}
|
||
|
|
self.links = []
|
||
|
|
self.fieldsets = []
|
||
|
|
self.fieldset_stack = []
|
||
|
|
self.disabled_ancestors = {}
|
||
|
|
self.feed(html)
|
||
|
|
def handle_starttag(self, tag, attributes):
|
||
|
|
attrs = dict(attributes)
|
||
|
|
if 'id' in attrs:
|
||
|
|
self.ids[attrs['id']] = attrs
|
||
|
|
self.disabled_ancestors[attrs['id']] = any('disabled' in parent for parent in self.fieldset_stack)
|
||
|
|
if tag == 'a':
|
||
|
|
self.links.append(attrs.get('href'))
|
||
|
|
if tag == 'fieldset':
|
||
|
|
self.fieldsets.append(attrs)
|
||
|
|
self.fieldset_stack.append(attrs)
|
||
|
|
|
||
|
|
def handle_endtag(self, tag):
|
||
|
|
if tag == 'fieldset' and self.fieldset_stack:
|
||
|
|
self.fieldset_stack.pop()
|
||
|
|
|
||
|
|
|
||
|
|
def render(name, permissions=None):
|
||
|
|
env = Environment(loader=ChoiceLoader([
|
||
|
|
DictLoader({'shared/frontend/base.html': '{% block extra_css %}{% endblock %}{% block content %}{% endblock %}{% block extra_js %}{% endblock %}'}),
|
||
|
|
FileSystemLoader('app'),
|
||
|
|
]), autoescape=True)
|
||
|
|
return env.get_template('workflows/frontend/'+name+'.html').render(
|
||
|
|
workflow_permissions=permissions or {}, time_id=12,
|
||
|
|
request=SimpleNamespace(url=SimpleNamespace(path='/workflows')))
|
||
|
|
|
||
|
|
|
||
|
|
def test_viewer_can_browse_without_write_controls_or_admin_links():
|
||
|
|
html = render('builder', {'view': True})
|
||
|
|
page = Elements(html)
|
||
|
|
assert 'disabled' in page.fieldsets[0]
|
||
|
|
for key in ('new', 'save', 'copy', 'disable', 'test', 'activate'):
|
||
|
|
assert 'hidden' in page.ids['wf-'+key]
|
||
|
|
assert '/workflows/operations' in page.links
|
||
|
|
assert '/workflows/resources' not in page.links
|
||
|
|
assert '/tags/classification' not in page.links
|
||
|
|
assert 'Henter workflows' in html
|
||
|
|
|
||
|
|
|
||
|
|
def test_manage_and_activation_are_separate_from_system_admin_navigation():
|
||
|
|
html = render('builder', {'view': True, 'manage': True, 'activate': True})
|
||
|
|
page = Elements(html)
|
||
|
|
assert 'disabled' not in page.fieldsets[0]
|
||
|
|
assert 'hidden' not in page.ids['wf-save']
|
||
|
|
assert 'hidden' not in page.ids['wf-activate']
|
||
|
|
assert '/workflows/resources' in page.links
|
||
|
|
assert '/tags/classification' not in page.links
|
||
|
|
assert '/tags/classification' in Elements(render('builder', {'system_admin': True})).links
|
||
|
|
|
||
|
|
|
||
|
|
def test_override_does_not_expose_reset_without_activation_permission():
|
||
|
|
page = Elements(render('decision', {'override': True}))
|
||
|
|
assert 'hidden' in page.ids['decision-reset']
|
||
|
|
assert 'hidden' not in Elements(render('decision', {'override': True, 'activate': True})).ids['decision-reset']
|
||
|
|
|
||
|
|
|
||
|
|
def test_activation_only_user_can_deactivate_without_editing_definition():
|
||
|
|
page = Elements(render('builder', {'view': True, 'activate': True}))
|
||
|
|
assert 'hidden' not in page.ids['wf-disable']
|
||
|
|
assert not page.disabled_ancestors['wf-disable']
|
||
|
|
assert 'hidden' in page.ids['wf-save']
|
||
|
|
|
||
|
|
|
||
|
|
def test_ops_permission_flags_are_rendered_as_booleans_for_dynamic_buttons():
|
||
|
|
readonly = render('operations', {'view': True})
|
||
|
|
assert 'const canManage=false,canExport=false;' in readonly
|
||
|
|
assert 'const canManage=true,canExport=true;' in render('operations', {'manage': True, 'economic_export': True})
|
||
|
|
|
||
|
|
|
||
|
|
def test_pages_share_theme_tokens_and_responsive_scope():
|
||
|
|
for name in ('builder', 'decision', 'resources', 'operations'):
|
||
|
|
html = render(name, {'view': True})
|
||
|
|
assert 'container-fluid workflow-page' in html
|
||
|
|
assert 'workflow-heading' in html
|
||
|
|
assert 'var(--bg-card' in html
|
||
|
|
assert 'var(--text-secondary' in html
|
||
|
|
assert '@media(max-width:576px)' in html
|