misc: split backoffice tests

This commit is contained in:
Lauréline Guérin 2021-08-19 12:15:27 +02:00
parent 3584fde29c
commit 3b9f87fb89
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
5 changed files with 755 additions and 672 deletions

View File

@ -0,0 +1,13 @@
import pytest
from quixote import get_publisher
@pytest.fixture
def local_user():
get_publisher().user_class.wipe()
user = get_publisher().user_class()
user.name = 'Jean Darmette'
user.email = 'jean.darmette@triffouilis.fr'
user.name_identifiers = ['0123456789']
user.store()
return user

View File

@ -9,8 +9,6 @@ import zipfile
from unittest import mock
import pytest
from quixote import get_publisher
from quixote.http_request import Upload as QuixoteUpload
import wcs.qommon.storage as st
from wcs import fields
@ -19,7 +17,6 @@ from wcs.blocks import BlockDef
from wcs.carddef import CardDef
from wcs.categories import Category
from wcs.formdef import FormDef
from wcs.qommon.form import UploadedFile
from wcs.qommon.http_request import HTTPRequest
from wcs.qommon.ident.password_accounts import PasswordAccount
from wcs.qommon.upload_storage import PicklableUpload
@ -28,7 +25,6 @@ from wcs.wf.backoffice_fields import SetBackofficeFieldsWorkflowStatusItem
from wcs.wf.create_carddata import CreateCarddataWorkflowStatusItem
from wcs.wf.create_formdata import CreateFormdataWorkflowStatusItem, Mapping
from wcs.wf.dispatch import DispatchWorkflowStatusItem
from wcs.wf.export_to_model import ExportToModel
from wcs.wf.form import FormWorkflowStatusItem, WorkflowFormFieldsFormDef
from wcs.wf.jump import JumpWorkflowStatusItem
from wcs.wf.redirect_to_url import RedirectToUrlWorkflowStatusItem
@ -4473,557 +4469,6 @@ def test_backoffice_criticality_formdata_view(pub):
assert 'Criticality Level: red' in resp.text
class IHateUnicode:
def __unicode__(self):
raise Exception('HATE!!')
def __repr__(self):
return 'ok'
@pytest.fixture
def local_user():
get_publisher().user_class.wipe()
user = get_publisher().user_class()
user.name = 'Jean Darmette'
user.email = 'jean.darmette@triffouilis.fr'
user.name_identifiers = ['0123456789']
user.store()
return user
def test_inspect_page(pub, local_user):
create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
formdef.fields.append(fields.FileField(id='4', label='file field', type='file', varname='file'))
formdef.store()
formdata = [x for x in formdef.data_class().select() if x.status == 'wf-new'][0]
# temper with field 3 structured values
formdata.data['3_structured'] = {
'unicode': 'uné',
'str_but_non_utf8': b'\xed\xa0\x00', # not actually supposed to happen
'non_unicode_convertible': IHateUnicode(),
'very_long_string': '0' * 100000,
}
# add a PicklableUpload in field 4
upload = PicklableUpload('hello.txt', content_type='text/plain')
upload.receive([b'hello world'])
formdata.data['4'] = upload
formdata.user_id = local_user.id
formdata.workflow_data = {
'foo': {
'bar_coin': 'yy',
},
'foo_bar': 'xx',
}
formdata.store()
from wcs.admin.settings import UserFieldsFormDef
user_formdef = UserFieldsFormDef(pub)
user_formdef.fields.append(fields.StringField(id='_first_name', label='name', type='string'))
user_formdef.fields.append(fields.StringField(id='3', label='test', type='string'))
user_formdef.store()
local_user.form_data = {'_first_name': 'toto', '3': 'nono'}
local_user.set_attributes_from_formdata(local_user.form_data)
local_user.store()
resp = login(get_app(pub)).get(formdata.get_url(backoffice=True), status=200)
assert 'Data Inspector' not in resp.text
resp = login(get_app(pub)).get('%sinspect' % formdata.get_url(backoffice=True), status=403)
create_user(pub, is_admin=True)
resp = login(get_app(pub)).get(formdata.get_url(backoffice=True), status=200)
resp = resp.click('Data Inspector')
assert '0' * 1000 in resp.text
assert len(resp.text) < 100000
pq = resp.pyquery.remove_namespaces()
assert pq('[title="form_var_foo_unicode"]').parents('li').children('div.value span').text() == 'uné'
assert (
pq('[title="form_var_foo_non_unicode_convertible"]')
.parents('li')
.children('div.value span')
.text()
.startswith('ok ')
)
assert (
pq('[title="form_var_foo_str_but_non_utf8"]').parents('li').children('div.value span').text()
== "b'\\xed\\xa0\\x00' (<class 'bytes'>)"
)
# don't show «unusable» variables
assert 'form_f1' not in resp.text
assert 'form_field_' not in resp.text
assert 'form_user_field_' not in resp.text
assert 'form_user_f3' not in resp.text
assert 'form_user_f_' not in resp.text
# make sure workflow data itself is not displayed, as it's available in
# expanded variables
assert not pq('[title="form_workflow_data"]')
# but do display it if it has some invalid contents
formdata.workflow_data['invalid key'] = 'foobar'
formdata.store()
resp = login(get_app(pub)).get(resp.request.url)
assert resp.pyquery('[title="form_workflow_data"]')
# check functions
assert re.findall('Recipient.*foobar', resp.text)
role = pub.role_class(name='plop')
role.store()
formdata.workflow_roles = {'_receiver': [role.id]}
formdata.store()
resp = login(get_app(pub)).get('%sinspect' % formdata.get_url(backoffice=True), status=200)
assert re.findall('Recipient.*plop', resp.text)
workflow = Workflow.get_default_workflow()
workflow.id = None
workflow.roles.update({'_plop': 'New Function'})
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
resp = login(get_app(pub)).get('%sinspect' % formdata.get_url(backoffice=True), status=200)
assert re.findall('New Function.*unset', resp.text)
formdata.workflow_roles = {'_receiver': [role.id], '_plop': ['123']}
formdata.store()
resp = login(get_app(pub)).get('%sinspect' % formdata.get_url(backoffice=True), status=200)
assert re.findall('New Function.*(deleted)', resp.text)
# test tools
app = login(get_app(pub))
resp = app.get('%sinspect' % formdata.get_url(backoffice=True), status=200)
assert "Test tool" in resp.text
resp.form['test_mode'] = 'python-condition'
resp.form['python-condition'] = 'len(form_name) == 10' # "form title"
resp = resp.form.submit()
assert 'Condition result' in resp.text
assert 'result-true' in resp.text
assert '<code>True</code>' in resp.text
resp.form['python-condition'] = 'len(form_name) == 5'
resp = resp.form.submit()
assert 'Condition result' in resp.text
assert 'result-false' in resp.text
assert '<code>False</code>' in resp.text
resp.form['python-condition'] = 'form_do_not_exist == 3'
resp = resp.form.submit()
assert 'Condition result' not in resp.text
assert 'Failed to evaluate condition' in resp.text
assert 'NameError' in resp.text
resp.form['test_mode'] = 'django-condition'
resp.form['django-condition'] = 'form_name|length == 10'
resp = resp.form.submit()
assert 'Condition result' in resp.text
assert 'result-true' in resp.text
resp.form['django-condition'] = 'form_name|length == 5'
resp = resp.form.submit()
assert 'Condition result' in resp.text
assert 'result-false' in resp.text
resp.form['django-condition'] = 'foo bar'
resp = resp.form.submit()
assert 'Condition result' not in resp.text
assert 'TemplateSyntaxError: Unused' in resp.text
resp.form['django-condition'] = 'form_name|length == 5'
ajax_resp = app.post(
'%sinspect-tool' % formdata.get_url(backoffice=True), params=resp.form.submit_fields()
)
assert ajax_resp.text.startswith('<div class="test-tool-result')
resp.form['test_mode'] = 'template'
resp.form['template'] = '{{ form_name }}'
resp = resp.form.submit()
assert 'Template rendering' in resp.text
assert '<div class="test-tool-result-plain">form title</div>' in resp.text
assert 'HTML Source' not in resp.text
assert 'rendered as an object' not in resp.text
resp.form['template'] = '<p>{{ form_name }}</p>'
resp = resp.form.submit()
assert 'Template rendering' in resp.text
assert '<p>form title</p>' in resp.text
assert 'HTML Source' in resp.text
assert 'rendered as an object' not in resp.text
resp.form['template'] = '{{ form_var_file }}'
resp = resp.form.submit()
assert 'Template rendering' in resp.text
assert '<div class="test-tool-result-plain">hello.txt</div>' in resp.text
assert 'rendered as an object' in resp.text
assert '<div class="test-tool-result-plain">hello.txt (PicklableUpload)</div>' in resp.text
assert 'HTML Source' not in resp.text
resp.form['template'] = '{% for x in 1 %}ok{% endfor %}'
resp = resp.form.submit()
assert 'Failed to evaluate template' in resp.text
assert 'TypeError' in resp.text
resp.form['template'] = '{% for x in 1 %}ok{% end %}'
resp = resp.form.submit()
assert 'syntax error' in resp.text
assert 'Invalid block tag' in resp.text
resp.form['template'] = ''
resp.form['test_mode'] = 'html_template'
resp.form['html_template'] = '<p>{{ form_name }}</p>'
resp = resp.form.submit()
resp = resp.form.submit()
assert 'Template rendering' in resp.text
assert '<p>form title</p>' in resp.text
assert 'HTML Source' in resp.text
resp.form['html_template'] = '{% for x in 1 %}ok{% endfor %}'
resp = resp.form.submit()
assert 'Failed to evaluate HTML template' in resp.text
assert 'TypeError' in resp.text
resp.form['html_template'] = '{% for x in 1 %}ok{% end %}'
resp = resp.form.submit()
assert 'syntax error' in resp.text
assert 'Invalid block tag' in resp.text
def test_inspect_page_with_related_objects(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
return
user = create_user(pub, is_admin=True)
FormDef.wipe()
CardDef.wipe()
# test ExternalWorkflowGlobalAction
external_wf = Workflow(name='External Workflow')
st1 = external_wf.add_status(name='New')
action = external_wf.add_global_action('Delete', 'delete')
action.append_item('remove')
trigger = action.append_trigger('webservice')
trigger.identifier = 'delete'
external_wf.store()
external_formdef = FormDef()
external_formdef.name = 'External Form'
external_formdef.fields = [
fields.StringField(id='0', label='string', varname='form_string'),
]
external_formdef.workflow = external_wf
external_formdef.store()
external_carddef = CardDef()
external_carddef.name = 'External Card'
external_carddef.fields = [
fields.StringField(id='0', label='string', varname='card_string'),
]
external_carddef.backoffice_submission_roles = user.roles
external_carddef.workflow = external_wf
external_carddef.store()
wf = Workflow(name='External actions')
st1 = wf.add_status('Create external formdata')
# add a message to history, to check it doesn't interfer when searching for
# linked data.
register_comment = RegisterCommenterWorkflowStatusItem()
register_comment.id = '_register'
register_comment.comment = '<p>test</p>'
st1.items.append(register_comment)
register_comment.parent = st1
create_formdata = CreateFormdataWorkflowStatusItem()
create_formdata.label = 'create linked form'
create_formdata.formdef_slug = external_formdef.url_name
create_formdata.varname = 'created_form'
create_formdata.id = '_create_form'
mappings = [Mapping(field_id='0', expression='{{ form_var_string }}')]
create_formdata.mappings = mappings
create_formdata.parent = st1
create_carddata = CreateCarddataWorkflowStatusItem()
create_carddata.label = 'create linked card'
create_carddata.formdef_slug = external_carddef.url_name
create_carddata.varname = 'created_card'
create_carddata.id = '_create_card'
create_carddata.mappings = mappings
create_carddata.parent = st1
st1.items.append(create_formdata)
st1.items.append(create_carddata)
global_action = wf.add_global_action('Delete external linked object', 'delete')
action = global_action.append_item('external_workflow_global_action')
action.slug = 'formdef:%s' % external_formdef.url_name
action.trigger_id = 'action:%s' % trigger.identifier
wf.store()
formdef = FormDef()
formdef.name = 'External action form'
formdef.fields = [
fields.StringField(id='0', label='string', varname='string'),
]
formdef.workflow = wf
formdef.store()
carddef = CardDef()
carddef.name = 'External action card'
carddef.fields = [
fields.StringField(id='0', label='string', varname='string'),
]
carddef.backoffice_submission_roles = user.roles
carddef.workflow = wf
carddef.store()
assert formdef.data_class().count() == 0
assert carddef.data_class().count() == 0
assert external_formdef.data_class().count() == 0
assert external_carddef.data_class().count() == 0
formdata = formdef.data_class()()
formdata.data = {'0': 'test form'}
formdata.user = user
formdata.store()
formdata.just_created()
formdata.perform_workflow()
assert formdef.data_class().count() == 1
assert carddef.data_class().count() == 0
# related form and card
assert external_formdef.data_class().count() == 1
assert external_carddef.data_class().count() == 1
app = login(get_app(pub))
resp = app.get('/backoffice/management/external-action-form/1/inspect')
assert 'Related Forms/Cards' in resp.text
# related form and card
assert (
'<li><a href="http://example.net/backoffice/management/external-form/1/">External Form #1-1 (Evolution)</a></li>'
in resp.text
)
assert (
'<li><a href="http://example.net/backoffice/data/external-card/1/">External Card #1-1 (Evolution)</a></li>'
in resp.text
)
# check related form
resp = app.get('/backoffice/management/external-form/1/')
assert (
'<h3>Original form</h3><p><a href="http://example.net/backoffice/management/external-action-form/1/">External action form #2-1</a></p>'
in resp.text
)
resp = app.get('/backoffice/management/external-form/1/inspect')
# parent
assert (
'<li><a href="http://example.net/backoffice/management/external-action-form/1/">External action form #2-1 (Parent)</a></li>'
in resp.text
)
# check related card
resp = app.get('/backoffice/data/external-card/1/')
assert (
'<h3>Original form</h3><p><a href="http://example.net/backoffice/management/external-action-form/1/">External action form #2-1</a></p>'
in resp.text
)
resp = app.get('/backoffice/data/external-card/1/inspect')
# parent
assert (
'<li><a href="http://example.net/backoffice/management/external-action-form/1/">External action form #2-1 (Parent)</a></li>'
in resp.text
)
external_formdef.data_class().wipe()
external_carddef.data_class().wipe()
# missing form/card data
resp = app.get('/backoffice/management/external-action-form/1/inspect')
assert 'Related Forms/Cards' in resp.text
assert (
'<li><a href="">Linked &quot;External Form&quot; object by id 1 (Evolution - not found)</a></li>'
in resp.text
)
assert (
'<li><a href="">Linked &quot;External Card&quot; object by id 1 (Evolution - not found)</a></li>'
in resp.text
)
formdef.data_class().wipe()
carddef.data_class().wipe()
carddata = carddef.data_class()()
carddata.data = {'0': 'test card'}
carddata.user = user
carddata.store()
carddata.just_created()
carddata.perform_workflow()
assert formdef.data_class().count() == 0
assert carddef.data_class().count() == 1
# related form and card
assert external_formdef.data_class().count() == 1
assert external_carddef.data_class().count() == 1
resp = app.get('/backoffice/data/external-action-card/1/inspect')
assert 'Related Forms/Cards' in resp.text
# related form and card
assert (
'<li><a href="http://example.net/backoffice/management/external-form/2/">External Form #1-2 (Evolution)</a></li>'
in resp.text
)
assert (
'<li><a href="http://example.net/backoffice/data/external-card/2/">External Card #1-2 (Evolution)</a></li>'
in resp.text
)
# check related form
resp = app.get('/backoffice/management/external-form/2/')
assert (
'<h3>Original card</h3><p><a href="http://example.net/backoffice/data/external-action-card/1/">External action card #2-1</a></p>'
in resp.text
)
resp = app.get('/backoffice/management/external-form/2/inspect')
# parent
assert (
'<li><a href="http://example.net/backoffice/data/external-action-card/1/">External action card #2-1 (Parent)</a></li>'
in resp.text
)
# check related card
resp = app.get('/backoffice/data/external-card/2/')
assert (
'<h3>Original card</h3><p><a href="http://example.net/backoffice/data/external-action-card/1/">External action card #2-1</a></p>'
in resp.text
)
resp = app.get('/backoffice/data/external-card/2/inspect')
# parent
assert (
'<li><a href="http://example.net/backoffice/data/external-action-card/1/">External action card #2-1 (Parent)</a></li>'
in resp.text
)
FormDef.wipe()
CardDef.wipe()
Workflow.wipe()
# test linked Card in datasource
wf = Workflow(name='WF')
st1 = wf.add_status('NEW')
wf.store()
wfc = Workflow(name='WFC')
wfc.add_status('NEW')
wfc.store()
carddef = CardDef()
carddef.name = 'CARD A'
carddef.fields = [
fields.StringField(id='0', label='string', varname='string'),
]
carddef.backoffice_submission_roles = user.roles
carddef.workflow = wfc
carddef.store()
datasource = {'type': 'carddef:%s' % carddef.url_name}
formdef = FormDef()
formdef.name = 'FORM A'
formdef.fields = [
fields.ItemField(id='0', label='Card', type='item', varname='card', data_source=datasource),
]
formdef.workflow = wf
formdef.store()
carddata = carddef.data_class()()
carddata.data = {'0': 'Text'}
carddata.store()
formdata = formdef.data_class()()
formdata.data = {'0': '1'}
formdata.store()
formdata.just_created()
formdata.perform_workflow()
assert formdef.data_class().count() == 1
assert carddef.data_class().count() == 1
resp = app.get('/backoffice/management/form-a/1/inspect')
assert 'Related Forms/Cards' in resp.text
# related card
assert (
'<li><a href="http://example.net/backoffice/data/card-a/1/">CARD A #1-1 (Data Source - varname &quot;card&quot;)</a></li>'
in resp.text
)
# missing carddata
carddef.data_class().wipe()
resp = app.get('/backoffice/management/form-a/1/inspect')
assert 'Related Forms/Cards' in resp.text
assert (
'<li><a href="">Linked &quot;CARD A&quot; object by id 1 (Data Source - varname &quot;card&quot; - not found)</a></li>'
in resp.text
)
# missing carddef
CardDef.wipe()
resp = app.get('/backoffice/management/form-a/1/inspect')
assert 'Related Forms/Cards' in resp.text
assert (
'<li><a href="">Linked object def by id card-a (Data Source - varname &quot;card&quot; - not found)</a></li>'
in resp.text
)
def test_inspect_page_actions_traces(pub):
create_environment(pub)
create_user(pub, is_admin=True)
workflow = Workflow.get_default_workflow()
workflow.id = '2'
workflow.criticality_levels = [
WorkflowCriticalityLevel(name='green'),
WorkflowCriticalityLevel(name='yellow'),
WorkflowCriticalityLevel(name='red'),
]
action = workflow.add_global_action('Timeout Test')
action.append_item('modify_criticality')
trigger = action.append_trigger('timeout')
trigger.anchor = 'creation'
trigger.timeout = '2'
workflow.store()
formdef = FormDef.get_by_urlname('form-title')
formdef.workflow_id = workflow.id
formdef.store()
formdef.data_class().wipe()
formdata = formdef.data_class()()
formdata.data = {}
formdata.just_created()
formdata.perform_workflow()
formdata.store()
# change receipt time to get global timeout to run
formdata.receipt_time = time.localtime(time.time() - 3 * 86400)
formdata.store()
pub.apply_global_action_timeouts()
formdata.refresh_from_storage()
assert formdata.get_criticality_level_object().name == 'yellow'
resp = login(get_app(pub)).get(formdata.get_url(backoffice=True), status=200)
resp = resp.click('Data Inspector')
assert '<h2>Actions Tracing</h2>' in resp
assert [x.text for x in resp.pyquery('#inspect-timeline strong')] == ['Just Submitted', 'New']
assert [x.text for x in resp.pyquery('#inspect-timeline a.tracing-link') if x.text] == [
'Email',
'Email',
'Automatic Jump',
'Criticality Levels',
]
action_links = [x.attrib['href'] for x in resp.pyquery('#inspect-timeline a.tracing-link')]
assert action_links[0] == 'http://example.net/backoffice/workflows/2/status/just_submitted/'
assert (
action_links[1]
== 'http://example.net/backoffice/workflows/2/status/just_submitted/items/_notify_new_receiver_email/'
)
assert action_links[-1] == 'http://example.net/backoffice/workflows/2/global-actions/1/items/1/'
def test_workflow_jump_previous(pub):
user = create_user(pub)
create_environment(pub)
@ -5659,112 +5104,6 @@ def test_backoffice_forms_condition_on_button(pub):
assert '8 open on 50' in resp.text # only the accepted ones
def test_workflow_inspect_page(pub):
admin = create_user(pub, is_admin=True)
create_environment(pub, set_receiver=True)
workflow = Workflow.get_default_workflow()
workflow.id = '2'
st1 = workflow.add_status('Status1')
jump = JumpWorkflowStatusItem()
jump.id = '_jump'
jump.timeout = '=86400'
jump.status = 'finished'
st1.items.append(jump)
jump.parent = st1
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/%s/inspect' % workflow.id)
assert '=86400' in resp.text
jump.timeout = '82800'
workflow.store()
resp = app.get('/backoffice/workflows/%s/inspect' % workflow.id)
assert '23 hours' in resp.text
target_formdef = FormDef()
target_formdef.name = 'target form'
target_formdef.workflow_roles = {'_receiver': 1}
target_formdef.backoffice_submission_roles = admin.roles[:]
target_formdef.fields = [
fields.StringField(id='0', label='string', varname='foo_string'),
fields.FileField(id='1', label='file', type='file', varname='foo_file'),
]
st2 = workflow.add_status('Status2')
target_formdef.store()
create_formdata = CreateFormdataWorkflowStatusItem()
create_formdata.id = '_create_formdata'
create_formdata.varname = 'resubmitted'
create_formdata.draft = True
create_formdata.formdef_slug = target_formdef.url_name
create_formdata.user_association_mode = 'keep-user'
create_formdata.backoffice_submission = True
create_formdata.mappings = [
Mapping(field_id='0', expression='=form_var_toto_string'),
Mapping(field_id='1', expression='=form_var_toto_file_raw'),
Mapping(field_id='2', expression='=form_var_foobar_raw'),
]
create_formdata.parent = st2
st2.items.append(create_formdata)
workflow.store()
resp = app.get('/backoffice/workflows/%s/inspect' % workflow.id)
assert (
'<ul class="mappings"><li>string → =form_var_toto_string</li>'
'<li>file → =form_var_toto_file_raw</li>'
'<li>#2 → =form_var_foobar_raw</li></ul>'
) in resp.text
workflow.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(workflow)
workflow.backoffice_fields_formdef.fields = [
fields.StringField(id='bo1', label='Foo Bar 1', varname='foo_bar'),
fields.StringField(id='bo2', label='Foo Bar 2', varname='foo_bar'),
fields.StringField(id='bo3', label='Foo Bar 3', varname='foo_bar'),
]
setbo = SetBackofficeFieldsWorkflowStatusItem()
setbo.parent = st2
setbo.fields = [
{'field_id': 'bo1', 'value': 'go'},
{'field_id': 'bo2', 'value': ''},
{'field_id': 'bo3', 'value': None},
{'field_id': 'unknown', 'value': 'foobar'},
]
st2.items.append(setbo)
workflow.store()
resp = app.get('/backoffice/workflows/%s/inspect' % workflow.id)
assert (
'<ul class="fields"><li>Foo Bar 1 → go</li>'
'<li>Foo Bar 2 → </li>'
'<li>Foo Bar 3 → None</li>'
'<li>#unknown → foobar</li></ul>'
) in resp.text
st3 = workflow.add_status('Status3', 'st3')
export_to = ExportToModel()
export_to.convert_to_pdf = False
export_to.label = 'create doc'
upload = QuixoteUpload('/foo/test.rtf', content_type='application/rtf')
upload.fp = io.BytesIO()
upload.fp.write(b'HELLO WORLD')
upload.fp.seek(0)
export_to.model_file = UploadedFile(pub.app_dir, None, upload)
export_to.id = '_export_to'
export_to.by = ['_submitter']
st3.items.append(export_to)
export_to.parent = st3
workflow.store()
resp = app.get('/backoffice/workflows/%s/inspect' % workflow.id)
assert (
'<li><span class="parameter">Model:</span> '
'<a href="status/st3/items/_export_to/?file=model_file">test.rtf</a></li>'
) in resp.text
def test_workflow_comment_required(pub):
create_user(pub)
create_environment(pub)

View File

@ -0,0 +1,601 @@
import re
import time
import pytest
from wcs import fields
from wcs.admin.settings import UserFieldsFormDef
from wcs.carddef import CardDef
from wcs.formdef import FormDef
from wcs.qommon.http_request import HTTPRequest
from wcs.qommon.upload_storage import PicklableUpload
from wcs.wf.create_carddata import CreateCarddataWorkflowStatusItem
from wcs.wf.create_formdata import CreateFormdataWorkflowStatusItem, Mapping
from wcs.wf.register_comment import RegisterCommenterWorkflowStatusItem
from wcs.workflows import Workflow, WorkflowCriticalityLevel
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app, login
from .test_all import create_user
def pytest_generate_tests(metafunc):
if 'pub' in metafunc.fixturenames:
metafunc.parametrize('pub', ['pickle', 'sql'], indirect=True)
@pytest.fixture
def pub(request, emails):
pub = create_temporary_pub(sql_mode=bool('sql' in request.param))
req = HTTPRequest(None, {'SCRIPT_NAME': '/', 'SERVER_NAME': 'example.net'})
pub.cfg['identification'] = {'methods': ['password']}
pub.cfg['language'] = {'language': 'en'}
pub.write_cfg()
pub.set_app_dir(req)
return pub
def teardown_module(module):
clean_temporary_pub()
class IHateUnicode:
def __unicode__(self):
raise Exception('HATE!!')
def __repr__(self):
return 'ok'
def test_inspect_page(pub, local_user):
create_user(pub)
formdef = FormDef()
formdef.name = 'form title'
datasource = {'type': 'formula', 'value': repr([('A', 'aa'), ('B', 'bb'), ('C', 'cc')])}
formdef.fields = [
fields.StringField(
id='1', label='1st field', type='string', display_locations=['validation', 'summary', 'listings']
),
fields.ItemField(
id='2',
label='2nd field',
type='item',
items=['foo', 'bar', 'baz'],
display_locations=['validation', 'summary', 'listings'],
),
fields.ItemField(id='3', label='3rd field', type='item', data_source=datasource, varname='foo'),
fields.FileField(id='4', label='file field', type='file', varname='file'),
]
formdef.workflow_roles = {'_receiver': 1}
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
upload = PicklableUpload('hello.txt', content_type='text/plain')
upload.receive([b'hello world'])
formdata.data = {
'1': 'FOO BAR 0',
'2': 'baz',
'2_display': 'baz',
'3': 'C',
'3_display': 'cc',
# temper with field 3 structured values
'3_structured': {
'unicode': 'uné',
'str_but_non_utf8': b'\xed\xa0\x00', # not actually supposed to happen
'non_unicode_convertible': IHateUnicode(),
'very_long_string': '0' * 100000,
},
# add a PicklableUpload in field 4
'4': upload,
}
formdata.jump_status('new')
formdata.user_id = local_user.id
formdata.workflow_data = {
'foo': {
'bar_coin': 'yy',
},
'foo_bar': 'xx',
}
formdata.store()
user_formdef = UserFieldsFormDef(pub)
user_formdef.fields.append(fields.StringField(id='_first_name', label='name', type='string'))
user_formdef.fields.append(fields.StringField(id='3', label='test', type='string'))
user_formdef.store()
local_user.form_data = {'_first_name': 'toto', '3': 'nono'}
local_user.set_attributes_from_formdata(local_user.form_data)
local_user.store()
resp = login(get_app(pub)).get(formdata.get_url(backoffice=True), status=200)
assert 'Data Inspector' not in resp.text
resp = login(get_app(pub)).get('%sinspect' % formdata.get_url(backoffice=True), status=403)
create_user(pub, is_admin=True)
resp = login(get_app(pub)).get(formdata.get_url(backoffice=True), status=200)
resp = resp.click('Data Inspector')
assert '0' * 1000 in resp.text
assert len(resp.text) < 100000
pq = resp.pyquery.remove_namespaces()
assert pq('[title="form_var_foo_unicode"]').parents('li').children('div.value span').text() == 'uné'
assert (
pq('[title="form_var_foo_non_unicode_convertible"]')
.parents('li')
.children('div.value span')
.text()
.startswith('ok ')
)
assert (
pq('[title="form_var_foo_str_but_non_utf8"]').parents('li').children('div.value span').text()
== "b'\\xed\\xa0\\x00' (<class 'bytes'>)"
)
# don't show «unusable» variables
assert 'form_f1' not in resp.text
assert 'form_field_' not in resp.text
assert 'form_user_field_' not in resp.text
assert 'form_user_f3' not in resp.text
assert 'form_user_f_' not in resp.text
# make sure workflow data itself is not displayed, as it's available in
# expanded variables
assert not pq('[title="form_workflow_data"]')
# but do display it if it has some invalid contents
formdata.workflow_data['invalid key'] = 'foobar'
formdata.store()
resp = login(get_app(pub)).get(resp.request.url)
assert resp.pyquery('[title="form_workflow_data"]')
# check functions
assert re.findall('Recipient.*foobar', resp.text)
role = pub.role_class(name='plop')
role.store()
formdata.workflow_roles = {'_receiver': [role.id]}
formdata.store()
resp = login(get_app(pub)).get('%sinspect' % formdata.get_url(backoffice=True), status=200)
assert re.findall('Recipient.*plop', resp.text)
workflow = Workflow.get_default_workflow()
workflow.id = None
workflow.roles.update({'_plop': 'New Function'})
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
resp = login(get_app(pub)).get('%sinspect' % formdata.get_url(backoffice=True), status=200)
assert re.findall('New Function.*unset', resp.text)
formdata.workflow_roles = {'_receiver': [role.id], '_plop': ['123']}
formdata.store()
resp = login(get_app(pub)).get('%sinspect' % formdata.get_url(backoffice=True), status=200)
assert re.findall('New Function.*(deleted)', resp.text)
# test tools
app = login(get_app(pub))
resp = app.get('%sinspect' % formdata.get_url(backoffice=True), status=200)
assert "Test tool" in resp.text
resp.form['test_mode'] = 'python-condition'
resp.form['python-condition'] = 'len(form_name) == 10' # "form title"
resp = resp.form.submit()
assert 'Condition result' in resp.text
assert 'result-true' in resp.text
assert '<code>True</code>' in resp.text
resp.form['python-condition'] = 'len(form_name) == 5'
resp = resp.form.submit()
assert 'Condition result' in resp.text
assert 'result-false' in resp.text
assert '<code>False</code>' in resp.text
resp.form['python-condition'] = 'form_do_not_exist == 3'
resp = resp.form.submit()
assert 'Condition result' not in resp.text
assert 'Failed to evaluate condition' in resp.text
assert 'NameError' in resp.text
resp.form['test_mode'] = 'django-condition'
resp.form['django-condition'] = 'form_name|length == 10'
resp = resp.form.submit()
assert 'Condition result' in resp.text
assert 'result-true' in resp.text
resp.form['django-condition'] = 'form_name|length == 5'
resp = resp.form.submit()
assert 'Condition result' in resp.text
assert 'result-false' in resp.text
resp.form['django-condition'] = 'foo bar'
resp = resp.form.submit()
assert 'Condition result' not in resp.text
assert 'TemplateSyntaxError: Unused' in resp.text
resp.form['django-condition'] = 'form_name|length == 5'
ajax_resp = app.post(
'%sinspect-tool' % formdata.get_url(backoffice=True), params=resp.form.submit_fields()
)
assert ajax_resp.text.startswith('<div class="test-tool-result')
resp.form['test_mode'] = 'template'
resp.form['template'] = '{{ form_name }}'
resp = resp.form.submit()
assert 'Template rendering' in resp.text
assert '<div class="test-tool-result-plain">form title</div>' in resp.text
assert 'HTML Source' not in resp.text
assert 'rendered as an object' not in resp.text
resp.form['template'] = '<p>{{ form_name }}</p>'
resp = resp.form.submit()
assert 'Template rendering' in resp.text
assert '<p>form title</p>' in resp.text
assert 'HTML Source' in resp.text
assert 'rendered as an object' not in resp.text
resp.form['template'] = '{{ form_var_file }}'
resp = resp.form.submit()
assert 'Template rendering' in resp.text
assert '<div class="test-tool-result-plain">hello.txt</div>' in resp.text
assert 'rendered as an object' in resp.text
assert '<div class="test-tool-result-plain">hello.txt (PicklableUpload)</div>' in resp.text
assert 'HTML Source' not in resp.text
resp.form['template'] = '{% for x in 1 %}ok{% endfor %}'
resp = resp.form.submit()
assert 'Failed to evaluate template' in resp.text
assert 'TypeError' in resp.text
resp.form['template'] = '{% for x in 1 %}ok{% end %}'
resp = resp.form.submit()
assert 'syntax error' in resp.text
assert 'Invalid block tag' in resp.text
resp.form['template'] = ''
resp.form['test_mode'] = 'html_template'
resp.form['html_template'] = '<p>{{ form_name }}</p>'
resp = resp.form.submit()
resp = resp.form.submit()
assert 'Template rendering' in resp.text
assert '<p>form title</p>' in resp.text
assert 'HTML Source' in resp.text
resp.form['html_template'] = '{% for x in 1 %}ok{% endfor %}'
resp = resp.form.submit()
assert 'Failed to evaluate HTML template' in resp.text
assert 'TypeError' in resp.text
resp.form['html_template'] = '{% for x in 1 %}ok{% end %}'
resp = resp.form.submit()
assert 'syntax error' in resp.text
assert 'Invalid block tag' in resp.text
def test_inspect_page_with_related_objects(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
return
user = create_user(pub, is_admin=True)
FormDef.wipe()
CardDef.wipe()
# test ExternalWorkflowGlobalAction
external_wf = Workflow(name='External Workflow')
st1 = external_wf.add_status(name='New')
action = external_wf.add_global_action('Delete', 'delete')
action.append_item('remove')
trigger = action.append_trigger('webservice')
trigger.identifier = 'delete'
external_wf.store()
external_formdef = FormDef()
external_formdef.name = 'External Form'
external_formdef.fields = [
fields.StringField(id='0', label='string', varname='form_string'),
]
external_formdef.workflow = external_wf
external_formdef.store()
external_carddef = CardDef()
external_carddef.name = 'External Card'
external_carddef.fields = [
fields.StringField(id='0', label='string', varname='card_string'),
]
external_carddef.backoffice_submission_roles = user.roles
external_carddef.workflow = external_wf
external_carddef.store()
wf = Workflow(name='External actions')
st1 = wf.add_status('Create external formdata')
# add a message to history, to check it doesn't interfer when searching for
# linked data.
register_comment = RegisterCommenterWorkflowStatusItem()
register_comment.id = '_register'
register_comment.comment = '<p>test</p>'
st1.items.append(register_comment)
register_comment.parent = st1
create_formdata = CreateFormdataWorkflowStatusItem()
create_formdata.label = 'create linked form'
create_formdata.formdef_slug = external_formdef.url_name
create_formdata.varname = 'created_form'
create_formdata.id = '_create_form'
mappings = [Mapping(field_id='0', expression='{{ form_var_string }}')]
create_formdata.mappings = mappings
create_formdata.parent = st1
create_carddata = CreateCarddataWorkflowStatusItem()
create_carddata.label = 'create linked card'
create_carddata.formdef_slug = external_carddef.url_name
create_carddata.varname = 'created_card'
create_carddata.id = '_create_card'
create_carddata.mappings = mappings
create_carddata.parent = st1
st1.items.append(create_formdata)
st1.items.append(create_carddata)
global_action = wf.add_global_action('Delete external linked object', 'delete')
action = global_action.append_item('external_workflow_global_action')
action.slug = 'formdef:%s' % external_formdef.url_name
action.trigger_id = 'action:%s' % trigger.identifier
wf.store()
formdef = FormDef()
formdef.name = 'External action form'
formdef.fields = [
fields.StringField(id='0', label='string', varname='string'),
]
formdef.workflow = wf
formdef.store()
carddef = CardDef()
carddef.name = 'External action card'
carddef.fields = [
fields.StringField(id='0', label='string', varname='string'),
]
carddef.backoffice_submission_roles = user.roles
carddef.workflow = wf
carddef.store()
assert formdef.data_class().count() == 0
assert carddef.data_class().count() == 0
assert external_formdef.data_class().count() == 0
assert external_carddef.data_class().count() == 0
formdata = formdef.data_class()()
formdata.data = {'0': 'test form'}
formdata.user = user
formdata.store()
formdata.just_created()
formdata.perform_workflow()
assert formdef.data_class().count() == 1
assert carddef.data_class().count() == 0
# related form and card
assert external_formdef.data_class().count() == 1
assert external_carddef.data_class().count() == 1
app = login(get_app(pub))
resp = app.get('/backoffice/management/external-action-form/1/inspect')
assert 'Related Forms/Cards' in resp.text
# related form and card
assert (
'<li><a href="http://example.net/backoffice/management/external-form/1/">External Form #1-1 (Evolution)</a></li>'
in resp.text
)
assert (
'<li><a href="http://example.net/backoffice/data/external-card/1/">External Card #1-1 (Evolution)</a></li>'
in resp.text
)
# check related form
resp = app.get('/backoffice/management/external-form/1/')
assert (
'<h3>Original form</h3><p><a href="http://example.net/backoffice/management/external-action-form/1/">External action form #2-1</a></p>'
in resp.text
)
resp = app.get('/backoffice/management/external-form/1/inspect')
# parent
assert (
'<li><a href="http://example.net/backoffice/management/external-action-form/1/">External action form #2-1 (Parent)</a></li>'
in resp.text
)
# check related card
resp = app.get('/backoffice/data/external-card/1/')
assert (
'<h3>Original form</h3><p><a href="http://example.net/backoffice/management/external-action-form/1/">External action form #2-1</a></p>'
in resp.text
)
resp = app.get('/backoffice/data/external-card/1/inspect')
# parent
assert (
'<li><a href="http://example.net/backoffice/management/external-action-form/1/">External action form #2-1 (Parent)</a></li>'
in resp.text
)
external_formdef.data_class().wipe()
external_carddef.data_class().wipe()
# missing form/card data
resp = app.get('/backoffice/management/external-action-form/1/inspect')
assert 'Related Forms/Cards' in resp.text
assert (
'<li><a href="">Linked &quot;External Form&quot; object by id 1 (Evolution - not found)</a></li>'
in resp.text
)
assert (
'<li><a href="">Linked &quot;External Card&quot; object by id 1 (Evolution - not found)</a></li>'
in resp.text
)
formdef.data_class().wipe()
carddef.data_class().wipe()
carddata = carddef.data_class()()
carddata.data = {'0': 'test card'}
carddata.user = user
carddata.store()
carddata.just_created()
carddata.perform_workflow()
assert formdef.data_class().count() == 0
assert carddef.data_class().count() == 1
# related form and card
assert external_formdef.data_class().count() == 1
assert external_carddef.data_class().count() == 1
resp = app.get('/backoffice/data/external-action-card/1/inspect')
assert 'Related Forms/Cards' in resp.text
# related form and card
assert (
'<li><a href="http://example.net/backoffice/management/external-form/2/">External Form #1-2 (Evolution)</a></li>'
in resp.text
)
assert (
'<li><a href="http://example.net/backoffice/data/external-card/2/">External Card #1-2 (Evolution)</a></li>'
in resp.text
)
# check related form
resp = app.get('/backoffice/management/external-form/2/')
assert (
'<h3>Original card</h3><p><a href="http://example.net/backoffice/data/external-action-card/1/">External action card #2-1</a></p>'
in resp.text
)
resp = app.get('/backoffice/management/external-form/2/inspect')
# parent
assert (
'<li><a href="http://example.net/backoffice/data/external-action-card/1/">External action card #2-1 (Parent)</a></li>'
in resp.text
)
# check related card
resp = app.get('/backoffice/data/external-card/2/')
assert (
'<h3>Original card</h3><p><a href="http://example.net/backoffice/data/external-action-card/1/">External action card #2-1</a></p>'
in resp.text
)
resp = app.get('/backoffice/data/external-card/2/inspect')
# parent
assert (
'<li><a href="http://example.net/backoffice/data/external-action-card/1/">External action card #2-1 (Parent)</a></li>'
in resp.text
)
FormDef.wipe()
CardDef.wipe()
Workflow.wipe()
# test linked Card in datasource
wf = Workflow(name='WF')
st1 = wf.add_status('NEW')
wf.store()
wfc = Workflow(name='WFC')
wfc.add_status('NEW')
wfc.store()
carddef = CardDef()
carddef.name = 'CARD A'
carddef.fields = [
fields.StringField(id='0', label='string', varname='string'),
]
carddef.backoffice_submission_roles = user.roles
carddef.workflow = wfc
carddef.store()
datasource = {'type': 'carddef:%s' % carddef.url_name}
formdef = FormDef()
formdef.name = 'FORM A'
formdef.fields = [
fields.ItemField(id='0', label='Card', type='item', varname='card', data_source=datasource),
]
formdef.workflow = wf
formdef.store()
carddata = carddef.data_class()()
carddata.data = {'0': 'Text'}
carddata.store()
formdata = formdef.data_class()()
formdata.data = {'0': '1'}
formdata.store()
formdata.just_created()
formdata.perform_workflow()
assert formdef.data_class().count() == 1
assert carddef.data_class().count() == 1
resp = app.get('/backoffice/management/form-a/1/inspect')
assert 'Related Forms/Cards' in resp.text
# related card
assert (
'<li><a href="http://example.net/backoffice/data/card-a/1/">CARD A #1-1 (Data Source - varname &quot;card&quot;)</a></li>'
in resp.text
)
# missing carddata
carddef.data_class().wipe()
resp = app.get('/backoffice/management/form-a/1/inspect')
assert 'Related Forms/Cards' in resp.text
assert (
'<li><a href="">Linked &quot;CARD A&quot; object by id 1 (Data Source - varname &quot;card&quot; - not found)</a></li>'
in resp.text
)
# missing carddef
CardDef.wipe()
resp = app.get('/backoffice/management/form-a/1/inspect')
assert 'Related Forms/Cards' in resp.text
assert (
'<li><a href="">Linked object def by id card-a (Data Source - varname &quot;card&quot; - not found)</a></li>'
in resp.text
)
def test_inspect_page_actions_traces(pub):
create_user(pub, is_admin=True)
workflow = Workflow.get_default_workflow()
workflow.id = '2'
workflow.criticality_levels = [
WorkflowCriticalityLevel(name='green'),
WorkflowCriticalityLevel(name='yellow'),
WorkflowCriticalityLevel(name='red'),
]
action = workflow.add_global_action('Timeout Test')
action.append_item('modify_criticality')
trigger = action.append_trigger('timeout')
trigger.anchor = 'creation'
trigger.timeout = '2'
workflow.store()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.workflow_id = workflow.id
formdef.store()
formdef.data_class().wipe()
formdata = formdef.data_class()()
formdata.data = {}
formdata.just_created()
formdata.perform_workflow()
formdata.store()
# change receipt time to get global timeout to run
formdata.receipt_time = time.localtime(time.time() - 3 * 86400)
formdata.store()
pub.apply_global_action_timeouts()
formdata.refresh_from_storage()
assert formdata.get_criticality_level_object().name == 'yellow'
resp = login(get_app(pub)).get(formdata.get_url(backoffice=True), status=200)
resp = resp.click('Data Inspector')
assert '<h2>Actions Tracing</h2>' in resp
assert [x.text for x in resp.pyquery('#inspect-timeline strong')] == ['Just Submitted', 'New']
assert [x.text for x in resp.pyquery('#inspect-timeline a.tracing-link') if x.text] == [
'Email',
'Email',
'Automatic Jump',
'Criticality Levels',
]
action_links = [x.attrib['href'] for x in resp.pyquery('#inspect-timeline a.tracing-link')]
assert action_links[0] == 'http://example.net/backoffice/workflows/2/status/just_submitted/'
assert (
action_links[1]
== 'http://example.net/backoffice/workflows/2/status/just_submitted/items/_notify_new_receiver_email/'
)
assert action_links[-1] == 'http://example.net/backoffice/workflows/2/global-actions/1/items/1/'

View File

@ -45,17 +45,6 @@ def pub(request, emails):
return pub
@pytest.fixture
def local_user(pub):
pub.user_class.wipe()
user = pub.user_class()
user.name = 'Jean Darmette'
user.email = 'jean.darmette@triffouilis.fr'
user.name_identifiers = ['0123456789']
user.store()
return user
def teardown_module(module):
clean_temporary_pub()

View File

@ -0,0 +1,141 @@
import io
import pytest
from quixote.http_request import Upload as QuixoteUpload
from wcs import fields
from wcs.formdef import FormDef
from wcs.qommon.form import UploadedFile
from wcs.qommon.http_request import HTTPRequest
from wcs.wf.backoffice_fields import SetBackofficeFieldsWorkflowStatusItem
from wcs.wf.create_formdata import CreateFormdataWorkflowStatusItem, Mapping
from wcs.wf.export_to_model import ExportToModel
from wcs.wf.jump import JumpWorkflowStatusItem
from wcs.workflows import Workflow, WorkflowBackofficeFieldsFormDef
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app, login
from .test_all import create_superuser
def pytest_generate_tests(metafunc):
if 'pub' in metafunc.fixturenames:
metafunc.parametrize('pub', ['pickle', 'sql'], indirect=True)
@pytest.fixture
def pub(request, emails):
pub = create_temporary_pub(sql_mode=bool('sql' in request.param))
req = HTTPRequest(None, {'SCRIPT_NAME': '/', 'SERVER_NAME': 'example.net'})
pub.cfg['identification'] = {'methods': ['password']}
pub.cfg['language'] = {'language': 'en'}
pub.write_cfg()
pub.set_app_dir(req)
return pub
def teardown_module(module):
clean_temporary_pub()
def test_workflow_inspect_page(pub):
admin = create_superuser(pub)
workflow = Workflow(name='blah')
st1 = workflow.add_status('Status1')
jump = JumpWorkflowStatusItem()
jump.id = '_jump'
jump.timeout = '=86400'
jump.status = 'finished'
st1.items.append(jump)
jump.parent = st1
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/%s/inspect' % workflow.id)
assert '=86400' in resp.text
jump.timeout = '82800'
workflow.store()
resp = app.get('/backoffice/workflows/%s/inspect' % workflow.id)
assert '23 hours' in resp.text
target_formdef = FormDef()
target_formdef.name = 'target form'
target_formdef.workflow_roles = {'_receiver': 1}
target_formdef.backoffice_submission_roles = admin.roles[:]
target_formdef.fields = [
fields.StringField(id='0', label='string', varname='foo_string'),
fields.FileField(id='1', label='file', type='file', varname='foo_file'),
]
st2 = workflow.add_status('Status2')
target_formdef.store()
create_formdata = CreateFormdataWorkflowStatusItem()
create_formdata.id = '_create_formdata'
create_formdata.varname = 'resubmitted'
create_formdata.draft = True
create_formdata.formdef_slug = target_formdef.url_name
create_formdata.user_association_mode = 'keep-user'
create_formdata.backoffice_submission = True
create_formdata.mappings = [
Mapping(field_id='0', expression='=form_var_toto_string'),
Mapping(field_id='1', expression='=form_var_toto_file_raw'),
Mapping(field_id='2', expression='=form_var_foobar_raw'),
]
create_formdata.parent = st2
st2.items.append(create_formdata)
workflow.store()
resp = app.get('/backoffice/workflows/%s/inspect' % workflow.id)
assert (
'<ul class="mappings"><li>string → =form_var_toto_string</li>'
'<li>file → =form_var_toto_file_raw</li>'
'<li>#2 → =form_var_foobar_raw</li></ul>'
) in resp.text
workflow.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(workflow)
workflow.backoffice_fields_formdef.fields = [
fields.StringField(id='bo1', label='Foo Bar 1', varname='foo_bar'),
fields.StringField(id='bo2', label='Foo Bar 2', varname='foo_bar'),
fields.StringField(id='bo3', label='Foo Bar 3', varname='foo_bar'),
]
setbo = SetBackofficeFieldsWorkflowStatusItem()
setbo.parent = st2
setbo.fields = [
{'field_id': 'bo1', 'value': 'go'},
{'field_id': 'bo2', 'value': ''},
{'field_id': 'bo3', 'value': None},
{'field_id': 'unknown', 'value': 'foobar'},
]
st2.items.append(setbo)
workflow.store()
resp = app.get('/backoffice/workflows/%s/inspect' % workflow.id)
assert (
'<ul class="fields"><li>Foo Bar 1 → go</li>'
'<li>Foo Bar 2 → </li>'
'<li>Foo Bar 3 → None</li>'
'<li>#unknown → foobar</li></ul>'
) in resp.text
st3 = workflow.add_status('Status3', 'st3')
export_to = ExportToModel()
export_to.convert_to_pdf = False
export_to.label = 'create doc'
upload = QuixoteUpload('/foo/test.rtf', content_type='application/rtf')
upload.fp = io.BytesIO()
upload.fp.write(b'HELLO WORLD')
upload.fp.seek(0)
export_to.model_file = UploadedFile(pub.app_dir, None, upload)
export_to.id = '_export_to'
export_to.by = ['_submitter']
st3.items.append(export_to)
export_to.parent = st3
workflow.store()
resp = app.get('/backoffice/workflows/%s/inspect' % workflow.id)
assert (
'<li><span class="parameter">Model:</span> '
'<a href="status/st3/items/_export_to/?file=model_file">test.rtf</a></li>'
) in resp.text