Merge branch 'dev' of github.com:sartography/cr-connect-workflow into dev

This commit is contained in:
Dan 2021-02-11 11:45:00 -05:00
commit d0f30c4f9c
11 changed files with 397 additions and 9 deletions

View File

@ -1,6 +1,7 @@
from SpiffWorkflow import WorkflowException from SpiffWorkflow import WorkflowException
from SpiffWorkflow.exceptions import WorkflowTaskExecException from SpiffWorkflow.exceptions import WorkflowTaskExecException
from flask import g from flask import g
from werkzeug.exceptions import InternalServerError
from crc import ma, app from crc import ma, app
@ -77,3 +78,9 @@ def handle_invalid_usage(error):
return response, error.status_code return response, error.status_code
@app.errorhandler(InternalServerError)
def handle_internal_server_error(e):
original = getattr(e, "original_exception", None)
api_error = ApiError(code='Internal Server Error (500)', message=str(original))
response = ApiErrorSchema().dump(api_error)
return response, 500

View File

@ -8,7 +8,7 @@ from marshmallow_enum import EnumField
from sqlalchemy import func from sqlalchemy import func
from crc import db, ma from crc import db, ma
from crc.api.common import ApiErrorSchema from crc.api.common import ApiErrorSchema, ApiError
from crc.models.file import FileModel, SimpleFileSchema, FileSchema from crc.models.file import FileModel, SimpleFileSchema, FileSchema
from crc.models.protocol_builder import ProtocolBuilderStatus, ProtocolBuilderStudy from crc.models.protocol_builder import ProtocolBuilderStatus, ProtocolBuilderStudy
from crc.models.workflow import WorkflowSpecCategoryModel, WorkflowState, WorkflowStatus, WorkflowSpecModel, \ from crc.models.workflow import WorkflowSpecCategoryModel, WorkflowState, WorkflowStatus, WorkflowSpecModel, \
@ -165,11 +165,14 @@ class Study(object):
@classmethod @classmethod
def from_model(cls, study_model: StudyModel): def from_model(cls, study_model: StudyModel):
id = study_model.id # Just read some value, in case the dict expired, otherwise dict may be empty. if study_model is not None and len(study_model.__dict__.items()) > 0:
args = dict((k, v) for k, v in study_model.__dict__.items() if not k.startswith('_')) args = dict((k, v) for k, v in study_model.__dict__.items() if not k.startswith('_'))
args['events_history'] = study_model.events_history # For some reason this attribute is not picked up args['events_history'] = study_model.events_history # For some reason this attribute is not picked up
instance = cls(**args) instance = cls(**args)
return instance return instance
else:
raise ApiError(code='empty_study_model',
message='There was a problem retrieving your study. StudyModel is empty.')
def model_args(self): def model_args(self):
"""Arguments that can be passed into the Study Model to update it.""" """Arguments that can be passed into the Study Model to update it."""

View File

@ -154,8 +154,14 @@ class WorkflowService(object):
result = WorkflowService.evaluate_property(Task.FIELD_PROP_LABEL_EXPRESSION, field, task) result = WorkflowService.evaluate_property(Task.FIELD_PROP_LABEL_EXPRESSION, field, task)
field.label = result field.label = result
# If the field is hidden, it should not produce a value. # If a field is hidden and required, it must have a default value or value_expression
if field.has_property(Task.FIELD_PROP_HIDE_EXPRESSION): if field.has_property(Task.FIELD_PROP_HIDE_EXPRESSION) and field.has_validation(Task.FIELD_CONSTRAINT_REQUIRED):
if not field.has_property(Task.FIELD_PROP_VALUE_EXPRESSION) or not (hasattr(field, 'default_value')):
raise ApiError(code='hidden and required field missing default',
message='Fields that are required but can be hidden must have either a default value or a value_expression')
# If the field is hidden and not required, it should not produce a value.
if field.has_property(Task.FIELD_PROP_HIDE_EXPRESSION) and not field.has_validation(Task.FIELD_CONSTRAINT_REQUIRED):
if WorkflowService.evaluate_property(Task.FIELD_PROP_HIDE_EXPRESSION, field, task): if WorkflowService.evaluate_property(Task.FIELD_PROP_HIDE_EXPRESSION, field, task):
continue continue
@ -256,6 +262,8 @@ class WorkflowService(object):
return None return None
if field.type == "enum" and not has_lookup: if field.type == "enum" and not has_lookup:
if isinstance(default, str) and default.strip() == '':
return
default_option = next((obj for obj in field.options if obj.id == default), None) default_option = next((obj for obj in field.options if obj.id == default), None)
if not default_option: if not default_option:
raise ApiError.from_task("invalid_default", "You specified a default value that does not exist in " raise ApiError.from_task("invalid_default", "You specified a default value that does not exist in "
@ -316,7 +324,11 @@ class WorkflowService(object):
data = db.session.query(LookupDataModel).filter( data = db.session.query(LookupDataModel).filter(
LookupDataModel.lookup_file_model == lookup_model).limit(10).all() LookupDataModel.lookup_file_model == lookup_model).limit(10).all()
options = [{"value": d.value, "label": d.label, "data": d.data} for d in data] options = [{"value": d.value, "label": d.label, "data": d.data} for d in data]
if len(options) > 0:
return random.choice(options) return random.choice(options)
else:
raise ApiError.from_task("invalid enum", "You specified an enumeration field (%s),"
" with no options" % field.id, task)
else: else:
raise ApiError.from_task("unknown_lookup_option", "The settings for this auto complete field " raise ApiError.from_task("unknown_lookup_option", "The settings for this auto complete field "
"are incorrect: %s " % field.id, task) "are incorrect: %s " % field.id, task)

Binary file not shown.

View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_0vm4ua3" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.2.0">
<bpmn:process id="Process_EmptyEnum" name="Empty Enum" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_08cjvuw</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_08cjvuw" sourceRef="StartEvent_1" targetRef="Activity_EmptyEnum" />
<bpmn:userTask id="Activity_EmptyEnum" name="Empty Enum" camunda:formKey="EmptyEnumForm">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="empty_select" label="Select One" type="enum">
<camunda:properties>
<camunda:property id="spreadsheet.name" value="empty_spreadsheet.xls" />
<camunda:property id="spreadsheet.value.column" value="COMPANY_ID" />
<camunda:property id="spreadsheet.label.column" value="COMPANY_NAME" />
</camunda:properties>
</camunda:formField>
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_08cjvuw</bpmn:incoming>
<bpmn:outgoing>Flow_0qm71qa</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_0qm71qa" sourceRef="Activity_EmptyEnum" targetRef="Activity_GoodBye" />
<bpmn:endEvent id="Event_034utr4">
<bpmn:incoming>Flow_0ynk21r</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_0ynk21r" sourceRef="Activity_GoodBye" targetRef="Event_034utr4" />
<bpmn:manualTask id="Activity_GoodBye" name="Good Bye">
<bpmn:documentation>&lt;H1&gt;Good Bye&lt;/H1&gt;</bpmn:documentation>
<bpmn:incoming>Flow_0qm71qa</bpmn:incoming>
<bpmn:outgoing>Flow_0ynk21r</bpmn:outgoing>
</bpmn:manualTask>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_EmptyEnum">
<bpmndi:BPMNEdge id="Flow_08cjvuw_di" bpmnElement="Flow_08cjvuw">
<di:waypoint x="215" y="117" />
<di:waypoint x="270" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0qm71qa_di" bpmnElement="Flow_0qm71qa">
<di:waypoint x="370" y="117" />
<di:waypoint x="430" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0ynk21r_di" bpmnElement="Flow_0ynk21r">
<di:waypoint x="530" y="117" />
<di:waypoint x="592" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1mqyx7y_di" bpmnElement="Activity_EmptyEnum">
<dc:Bounds x="270" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_034utr4_di" bpmnElement="Event_034utr4">
<dc:Bounds x="592" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0obcp1b_di" bpmnElement="Activity_GoodBye">
<dc:Bounds x="430" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_1mhc2v8" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.2.0">
<bpmn:process id="Process_HiddenRequired" name="Hidden Reguired Field" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_0zt7wv5</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0zt7wv5" sourceRef="StartEvent_1" targetRef="Activity_Hello" />
<bpmn:userTask id="Activity_HiddenField" name="Hidden Field" camunda:formKey="HiddenFieldForm">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="name" label="Name" type="string">
<camunda:properties>
<camunda:property id="hide_expression" value="hide_yes_no" />
</camunda:properties>
<camunda:validation>
<camunda:constraint name="required" config="require_yes_no" />
</camunda:validation>
</camunda:formField>
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0fb4w15</bpmn:incoming>
<bpmn:outgoing>Flow_0c2rym0</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_0cm6imh" sourceRef="Activity_Hello" targetRef="Activity_PreData" />
<bpmn:scriptTask id="Activity_PreData" name="Pre Data">
<bpmn:incoming>Flow_0cm6imh</bpmn:incoming>
<bpmn:outgoing>Flow_0fb4w15</bpmn:outgoing>
<bpmn:script>if not 'require_yes_no' in globals():
require_yes_no = True
if not 'hide_yes_no' in globals():
hide_yes_no = True</bpmn:script>
</bpmn:scriptTask>
<bpmn:sequenceFlow id="Flow_0fb4w15" sourceRef="Activity_PreData" targetRef="Activity_HiddenField" />
<bpmn:manualTask id="Activity_GoodBye" name="Good Bye">
<bpmn:documentation>&lt;H1&gt;Good Bye{% if name %} {{ name }}{% endif %}&lt;/H1&gt;</bpmn:documentation>
<bpmn:incoming>Flow_1qkjkbh</bpmn:incoming>
<bpmn:outgoing>Flow_1udbzd6</bpmn:outgoing>
</bpmn:manualTask>
<bpmn:endEvent id="Event_194gjyj">
<bpmn:incoming>Flow_1udbzd6</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1udbzd6" sourceRef="Activity_GoodBye" targetRef="Event_194gjyj" />
<bpmn:manualTask id="Activity_Hello" name="Hello">
<bpmn:documentation>&lt;H1&gt;Hello&lt;/H1&gt;</bpmn:documentation>
<bpmn:incoming>Flow_0zt7wv5</bpmn:incoming>
<bpmn:outgoing>Flow_0cm6imh</bpmn:outgoing>
</bpmn:manualTask>
<bpmn:sequenceFlow id="Flow_0c2rym0" sourceRef="Activity_HiddenField" targetRef="Activity_CheckDefault" />
<bpmn:sequenceFlow id="Flow_1qkjkbh" sourceRef="Activity_CheckDefault" targetRef="Activity_GoodBye" />
<bpmn:userTask id="Activity_CheckDefault" name="Check Default" camunda:formKey="CheckDefaultForm">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="color" label="Color" type="string" defaultValue="Gray">
<camunda:properties>
<camunda:property id="hide_expression" value="True" />
</camunda:properties>
<camunda:validation>
<camunda:constraint name="required" config="True" />
</camunda:validation>
</camunda:formField>
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0c2rym0</bpmn:incoming>
<bpmn:outgoing>Flow_1qkjkbh</bpmn:outgoing>
</bpmn:userTask>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_HiddenRequired">
<bpmndi:BPMNEdge id="Flow_0fb4w15_di" bpmnElement="Flow_0fb4w15">
<di:waypoint x="530" y="117" />
<di:waypoint x="590" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0cm6imh_di" bpmnElement="Flow_0cm6imh">
<di:waypoint x="370" y="117" />
<di:waypoint x="430" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0zt7wv5_di" bpmnElement="Flow_0zt7wv5">
<di:waypoint x="215" y="117" />
<di:waypoint x="270" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0c2rym0_di" bpmnElement="Flow_0c2rym0">
<di:waypoint x="690" y="117" />
<di:waypoint x="750" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1qkjkbh_di" bpmnElement="Flow_1qkjkbh">
<di:waypoint x="850" y="117" />
<di:waypoint x="910" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1udbzd6_di" bpmnElement="Flow_1udbzd6">
<di:waypoint x="1010" y="117" />
<di:waypoint x="1072" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0a4wzou_di" bpmnElement="Activity_HiddenField">
<dc:Bounds x="590" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0kjyqk8_di" bpmnElement="Activity_PreData">
<dc:Bounds x="430" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0v7ietz_di" bpmnElement="Activity_Hello">
<dc:Bounds x="270" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_12r6tn2_di" bpmnElement="Activity_GoodBye">
<dc:Bounds x="910" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_194gjyj_di" bpmnElement="Event_194gjyj">
<dc:Bounds x="1072" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0y8y596_di" bpmnElement="Activity_CheckDefault">
<dc:Bounds x="750" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_0l37fag" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.2.0">
<bpmn:process id="Process_TestValueExpression" name="Test Value Expression" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_1nc3qi5</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_1nc3qi5" sourceRef="StartEvent_1" targetRef="Activity_Hello" />
<bpmn:sequenceFlow id="Flow_1t2lo17" sourceRef="Activity_Hello" targetRef="Activity_PreData" />
<bpmn:sequenceFlow id="Flow_1hhfj67" sourceRef="Activity_PreData" targetRef="Activity_Data" />
<bpmn:manualTask id="Activity_Hello" name="Hello">
<bpmn:documentation>&lt;H1&gt;Hello&lt;/H1&gt;</bpmn:documentation>
<bpmn:incoming>Flow_1nc3qi5</bpmn:incoming>
<bpmn:outgoing>Flow_1t2lo17</bpmn:outgoing>
</bpmn:manualTask>
<bpmn:scriptTask id="Activity_PreData" name="Pre Data">
<bpmn:incoming>Flow_1t2lo17</bpmn:incoming>
<bpmn:outgoing>Flow_1hhfj67</bpmn:outgoing>
<bpmn:script>if not 'value_expression_value' in globals():
value_expression_value = ""</bpmn:script>
</bpmn:scriptTask>
<bpmn:userTask id="Activity_Data" name="Data" camunda:formKey="DataForm">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="color" label="Select" type="enum">
<camunda:properties>
<camunda:property id="value_expression" value="value_expression_value" />
</camunda:properties>
<camunda:value id="black" name="Black" />
<camunda:value id="white" name="White" />
</camunda:formField>
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1hhfj67</bpmn:incoming>
<bpmn:outgoing>Flow_1skkg5a</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_1skkg5a" sourceRef="Activity_Data" targetRef="Activity_GoodBye" />
<bpmn:manualTask id="Activity_GoodBye" name="Good Bye">
<bpmn:documentation>&lt;H1&gt;Good Bye&lt;/H1&gt;</bpmn:documentation>
<bpmn:incoming>Flow_1skkg5a</bpmn:incoming>
<bpmn:outgoing>Flow_057as2q</bpmn:outgoing>
</bpmn:manualTask>
<bpmn:endEvent id="Event_06wbkzi">
<bpmn:incoming>Flow_057as2q</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_057as2q" sourceRef="Activity_GoodBye" targetRef="Event_06wbkzi" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_TestValueExpression">
<bpmndi:BPMNEdge id="Flow_1nc3qi5_di" bpmnElement="Flow_1nc3qi5">
<di:waypoint x="215" y="117" />
<di:waypoint x="270" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1t2lo17_di" bpmnElement="Flow_1t2lo17">
<di:waypoint x="370" y="117" />
<di:waypoint x="431" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1hhfj67_di" bpmnElement="Flow_1hhfj67">
<di:waypoint x="531" y="117" />
<di:waypoint x="590" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1skkg5a_di" bpmnElement="Flow_1skkg5a">
<di:waypoint x="690" y="117" />
<di:waypoint x="750" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_057as2q_di" bpmnElement="Flow_057as2q">
<di:waypoint x="850" y="117" />
<di:waypoint x="912" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0hi68vh_di" bpmnElement="Activity_Hello">
<dc:Bounds x="270" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1i60o9l_di" bpmnElement="Activity_Data">
<dc:Bounds x="590" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1b8d6dc_di" bpmnElement="Activity_GoodBye">
<dc:Bounds x="750" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_06wbkzi_di" bpmnElement="Event_06wbkzi">
<dc:Bounds x="912" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_115dslj_di" bpmnElement="Activity_PreData">
<dc:Bounds x="431" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,18 @@
from tests.base_test import BaseTest
from crc import session
from crc.models.study import StudyModel
import json
class TestGetStudyFromModel(BaseTest):
def test_get_study_from_model(self):
self.load_example_data()
study = session.query(StudyModel).order_by(StudyModel.id.desc()).first()
id = study.id + 1
result = self.app.get('/v1.0/study/%i' % id,
headers=self.logged_in_headers())
json_data = json.loads(result.get_data(as_text=True))
self.assertIn('code', json_data)
self.assertEqual('empty_study_model', json_data['code'])

View File

@ -0,0 +1,13 @@
from tests.base_test import BaseTest
import json
class TestEmptyEnumList(BaseTest):
def test_empty_enum_list(self):
spec_model = self.load_test_spec('enum_empty_list')
rv = self.app.get('/v1.0/workflow-specification/%s/validate' % spec_model.id, headers=self.logged_in_headers())
json_data = json.loads(rv.get_data(as_text=True))
self.assertEqual(json_data[0]['code'], 'invalid enum')

View File

@ -0,0 +1,37 @@
from tests.base_test import BaseTest
import json
class TestWorkflowHiddenRequiredField(BaseTest):
def test_require_default(self):
# We have a field that can be hidden and required.
# Validation should fail if we don't have a default value.
spec_model = self.load_test_spec('hidden_required_field')
rv = self.app.get('/v1.0/workflow-specification/%s/validate' % spec_model.id, headers=self.logged_in_headers())
json_data = json.loads(rv.get_data(as_text=True))
self.assertEqual(json_data[0]['code'], 'hidden and required field missing default')
def test_default_used(self):
# If a field is hidden and required, make sure we use the default value
workflow = self.create_workflow('hidden_required_field')
workflow_api = self.get_workflow_api(workflow)
first_task = workflow_api.next_task
self.assertEqual('Activity_Hello', first_task.name)
workflow_api = self.get_workflow_api(workflow)
self.complete_form(workflow_api, first_task, {})
workflow_api = self.get_workflow_api(workflow)
second_task = workflow_api.next_task
self.assertEqual('Activity_HiddenField', second_task.name)
self.complete_form(workflow_api, second_task, {})
workflow_api = self.get_workflow_api(workflow)
# The color field is hidden and required. Make sure we use the default value
third_task = workflow_api.next_task
self.assertEqual('Activity_CheckDefault', third_task.name)
self.assertEqual('Gray', third_task.data['color'])

View File

@ -0,0 +1,31 @@
from tests.base_test import BaseTest
class TestValueExpression(BaseTest):
def test_value_expression_no_default(self):
workflow = self.create_workflow('test_value_expression')
workflow_api = self.get_workflow_api(workflow)
first_task = workflow_api.next_task
self.complete_form(workflow_api, first_task, {'value_expression_value': ''})
workflow_api = self.get_workflow_api(workflow)
second_task = workflow_api.next_task
self.assertEqual('', second_task.data['value_expression_value'])
self.assertNotIn('color', second_task.data)
def test_value_expression_with_default(self):
workflow = self.create_workflow('test_value_expression')
workflow_api = self.get_workflow_api(workflow)
first_task = workflow_api.next_task
self.complete_form(workflow_api, first_task, {'value_expression_value': 'black'})
workflow_api = self.get_workflow_api(workflow)
second_task = workflow_api.next_task
self.assertEqual('black', second_task.data['value_expression_value'])
self.assertIn('color', second_task.data)
self.assertEqual('black', second_task.data['color']['value'])