def _get_app(self): from corehq.apps.app_manager.tests.app_factory import AppFactory factory = AppFactory() factory.new_basic_module('m0', 'case1') factory.new_basic_module('m1', 'case2') factory.new_advanced_module('m2', 'case3') return factory.app
def test_form_display_condition(self): """ case_id should be renamed in a basic submodule form """ factory = AppFactory(domain=DOMAIN) m0, m0f0 = factory.new_advanced_module('parent', 'gold-fish') factory.form_requires_case(m0f0) # changing this case tag should result in the session var in the submodule entry being updated to match it m0f0.actions.load_update_cases[0].case_tag = 'load_goldfish_renamed' m1, m1f0 = factory.new_advanced_module('child', 'guppy', parent_module=m0) factory.form_requires_case(m1f0, 'gold-fish', update={'question1': '/data/question1'}) factory.form_requires_case(m1f0, 'guppy', parent_case_type='gold-fish') # making this case tag the same as the one in the parent module should mean that it will also get changed # to avoid conflicts m1f0.actions.load_update_cases[1].case_tag = 'load_goldfish_renamed' m1f0.form_filter = "#case/age > 33" XML = """ <partial> <menu id="m1" root="m0"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0" relevant="instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/case_id_load_goldfish_renamed_guppy]/age > 33"/> </menu> </partial> """ self.assertXmlPartialEqual(XML, factory.app.create_suite(), "./menu[@id='m1']")
def test_empty_module_errors(self, *args): factory = AppFactory(build_version='2.24.0') app = factory.app m1 = factory.new_basic_module('register', 'case', with_form=False) factory.new_advanced_module('update', 'case', with_form=False) m2 = factory.new_basic_module('update', 'case', with_form=False) m2.case_list = CaseList(show=True, label={'en': "case_list"}) factory.new_shadow_module('update', m1, with_form=False) errors = app.validate_app() standard_module_error = { 'type': 'no forms or case list', 'module': { 'id': 0, 'name': { 'en': 'register module' } }, } advanced_module_error = { 'type': 'no forms or case list', 'module': { 'id': 1, 'name': { 'en': 'update module' } }, } self._clean_unique_id(errors) self.assertEqual(len(errors), 2) self.assertIn(standard_module_error, errors) self.assertIn(advanced_module_error, errors)
def _get_app(self): from corehq.apps.app_manager.tests.app_factory import AppFactory factory = AppFactory() factory.new_basic_module("m0", "case1") factory.new_basic_module("m1", "case2") factory.new_advanced_module("m2", "case3") return factory.app
def test_inline_case_detail_from_another_module(self, *args): factory = AppFactory() module0, form0 = factory.new_advanced_module("m0", "person") factory.form_requires_case(form0, "person") module0.case_details.short.use_case_tiles = True self._add_columns_for_case_details(module0) module1, form1 = factory.new_advanced_module("m1", "person") factory.form_requires_case(form1, "person") # not configured to use other module's persistent case tile so # has no detail-inline and detail-persistent attr self.ensure_module_session_datum_xml(factory, '', '') # configured to use other module's persistent case tile module1.case_details.short.persistent_case_tile_from_module = module0.unique_id self.ensure_module_session_datum_xml( factory, '', 'detail-persistent="m0_case_short"') # configured to use other module's persistent case tile that has custom xml module0.case_details.short.use_case_tiles = False module0.case_details.short.custom_xml = '<detail id="m0_case_short"></detail>' self.ensure_module_session_datum_xml( factory, '', 'detail-persistent="m0_case_short"') module0.case_details.short.custom_xml = '' module0.case_details.short.use_case_tiles = True # configured to use pull down tile from the other module module1.case_details.short.pull_down_tile = True self.ensure_module_session_datum_xml( factory, 'detail-inline="m0_case_long"', 'detail-persistent="m0_case_short"') # set to use persistent case tile of its own as well but it would still # persists case tiles and detail inline from another module module1.case_details.short.use_case_tiles = True module1.case_details.short.persist_tile_on_forms = True self._add_columns_for_case_details(module1) self.ensure_module_session_datum_xml( factory, 'detail-inline="m0_case_long"', 'detail-persistent="m0_case_short"') # set to use case tile from a module that does not support case tiles anymore # and has own persistent case tile as well # So now detail inline from its own details module0.case_details.short.use_case_tiles = False self.ensure_module_session_datum_xml( factory, 'detail-inline="m1_case_long"', 'detail-persistent="m1_case_short"') # set to use case tile from a module that does not support case tiles anymore # and does not have its own persistent case tile as well module1.case_details.short.use_case_tiles = False self.ensure_module_session_datum_xml(factory, '', '')
def test_reference_to_missing_session_variable_in_stack(self): # http://manage.dimagi.com/default.asp?236750 # # Stack create blocks do not update the session after each datum # so items put into the session in one step aren't available later steps # # <datum id="case_id_A" value="instance('commcaresession')/session/data/case_id_new_A"/> # - <datum id="case_id_B" value="instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/case_id_A]/index/host"/> # + <datum id="case_id_B" value="instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/case_id_new_A]/index/host"/> # # in the above example ``case_id_A`` is being added to the session and then # later referenced. However since the session doesn't get updated # the value isn't available in the session. # # To fix this we need to replace any references to previous variables with the full xpath which # that session variable references. # # See corehq.apps.app_manager.suite_xml.post_process.workflow._replace_session_references_in_stack factory = AppFactory(build_version='2.9.0/latest') m0, m0f0 = factory.new_basic_module('person registration', 'person') factory.form_opens_case(m0f0) m1, m1f0 = factory.new_advanced_module('episode registration', 'episode') factory.form_requires_case(m1f0, case_type='person') factory.form_opens_case(m1f0, case_type='episode', is_subcase=True, is_extension=True) m2, m2f0 = factory.new_advanced_module('tests', 'episode') factory.form_requires_case(m2f0, 'episode') factory.advanced_form_autoloads(m2f0, AUTO_SELECT_CASE, 'host', 'load_episode_0') m1f0.post_form_workflow = WORKFLOW_FORM m1f0.form_links = [ FormLink( xpath="true()", form_id=m2f0.unique_id, datums=[ FormDatum( name='case_id_load_episode_0', xpath= "instance('commcaresession')/session/data/case_id_new_episode_0" ) ]), ] self.assertXmlPartialEqual(self.get_xml('form_link_enikshay'), factory.app.create_suite(), "./entry")
def test_case_list_registration_form_advanced(self): factory = AppFactory(build_version='2.9.0') register_module, register_form = factory.new_advanced_module('register_dugong', 'dugong') factory.form_opens_case(register_form) case_module, update_form = factory.new_advanced_module('update_dugong', 'dugong') factory.form_requires_case(update_form) case_module.case_list_form.form_id = register_form.get_unique_id() case_module.case_list_form.label = { 'en': 'Register another Dugong' } self.assertXmlEqual(self.get_xml('case-list-form-advanced'), factory.app.create_suite())
def _make_app_with_shadow_forms(self): factory = AppFactory('upstream', "Upstream App", include_xmlns=True) module1, form1 = factory.new_advanced_module('M1', 'casetype') factory.new_form(module1) module2, form2 = factory.new_advanced_module('M2', 'casetype') factory.new_form(module2) self._make_shadow_form(factory, 'M3', form1) self._make_shadow_form(factory, 'M4', form2) factory.app.save() self.addCleanup(factory.app.delete) # the test form names are unique form_names = [f.name['en'] for f in factory.app.get_forms()] self.assertEqual(len(form_names), len(set(form_names))) return factory.app
def test_case_list_registration_form_advanced(self): factory = AppFactory(build_version='2.9') register_module, register_form = factory.new_advanced_module('register_dugong', 'dugong') factory.form_opens_case(register_form) case_module, update_form = factory.new_advanced_module('update_dugong', 'dugong') factory.form_updates_case(update_form) case_module.case_list_form.form_id = register_form.get_unique_id() case_module.case_list_form.label = { 'en': 'Register another Dugong' } self.assertXmlEqual(self.get_xml('case-list-form-advanced'), factory.app.create_suite())
def test_incorrect_case_var_for_case_update(self): # see http://manage.dimagi.com/default.asp?230013 factory = AppFactory(build_version='2.9.0') new_episode_module, new_episode_form = factory.new_basic_module( 'register_episode', 'episode') factory.form_opens_case(new_episode_form) lab_test_module, lab_test_form = factory.new_advanced_module( 'lab_test', 'episode') factory.form_requires_case(lab_test_form, 'episode') factory.form_opens_case(lab_test_form, 'lab_test', is_subcase=True, is_extension=True) factory.form_opens_case(lab_test_form, 'lab_referral', is_subcase=True, parent_tag='open_lab_test') lab_update_module, lab_update_form = factory.new_advanced_module( 'lab_update', 'lab_test', parent_module=lab_test_module) factory.form_requires_case(lab_update_form, 'episode', update={'episode_type': '/data/question1'}) factory.form_requires_case(lab_update_form, 'lab_test', parent_case_type='episode') lab_update_form.source = self.get_xml( 'original_form', override_path=('data', )).decode('utf-8') expected_suite_entry = """ <partial> <session> <datum id="case_id_load_episode_0" nodeset="instance('casedb')/casedb/case[@case_type='episode'][@status='open']" value="./@case_id" detail-select="m0_case_short"/> <datum id="case_id_new_lab_test_0" function="uuid()"/> <datum id="case_id_new_lab_referral_1" function="uuid()"/> <datum id="case_id_load_lab_test_0" nodeset="instance('casedb')/casedb/case[@case_type='lab_test'][@status='open'][index/parent=instance('commcaresession')/session/data/case_id_load_episode_0]" value="./@case_id" detail-select="m2_case_short" detail-confirm="m2_case_long"/> </session> </partial>""" suite_xml = factory.app.create_suite() self.assertXmlPartialEqual(expected_suite_entry, suite_xml, './entry[3]/session') form_xml = lab_update_form.render_xform().decode('utf-8') self.assertTrue( '<bind calculate="instance(\'commcaresession\')/session/data/case_id_new_lab_test_0" nodeset="/data/case_load_episode_0/case/@case_id"/>' not in form_xml) self.assertTrue( '<bind calculate="instance(\'commcaresession\')/session/data/case_id_load_episode_0" nodeset="/data/case_load_episode_0/case/@case_id"/>' in form_xml)
def test_return_to_child_module(self): factory = AppFactory(build_version='2.9.0/latest') m0, m0f0 = factory.new_basic_module('enroll child', 'child') factory.form_opens_case(m0f0) m1, m1f0 = factory.new_basic_module('child visit', 'child') factory.form_requires_case(m1f0) factory.form_opens_case(m1f0, case_type='visit', is_subcase=True) m2, m2f0 = factory.new_advanced_module('visit history', 'visit', parent_module=m1) factory.form_requires_case(m2f0, 'child') factory.form_requires_case(m2f0, 'visit', parent_case_type='child') m2f0.post_form_workflow = WORKFLOW_MODULE expected = """ <partial> <stack> <create> <command value="'m1'"/> <datum id="case_id" value="instance('commcaresession')/session/data/case_id"/> <datum id="case_id_new_visit_0" value="uuid()"/> <command value="'m2'"/> </create> </stack> </partial> """ self.assertXmlPartialEqual(expected, factory.app.create_suite(), "./entry[3]/stack")
def test_form_links_submodule(self): # Test that when linking between two forms in a submodule we match up the # session variables between the source and target form correctly factory = AppFactory(build_version='2.9.0/latest') m0, m0f0 = factory.new_basic_module('child visit', 'child') factory.form_requires_case(m0f0) factory.form_opens_case(m0f0, 'visit', is_subcase=True) m1, m1f0 = factory.new_advanced_module('visit histroy', 'visit', parent_module=m0) factory.form_requires_case(m1f0, 'child') factory.form_requires_case(m1f0, 'visit', parent_case_type='child') m1f1 = factory.new_form(m1) factory.form_requires_case(m1f1, 'child') factory.form_requires_case(m1f1, 'visit', parent_case_type='child') m1f0.post_form_workflow = WORKFLOW_FORM m1f0.form_links = [ FormLink(xpath="true()", form_id=m1f1.unique_id), ] self.assertXmlPartialEqual(self.get_xml('form_link_submodule'), factory.app.create_suite(), "./entry")
def test_custom_xml_with_wrong_module_index(self, *args): factory = AppFactory() module, form = factory.new_advanced_module("my_module", "person") # This should be 'm0_case_short' module.case_details.short.custom_xml = '<detail id="m1_case_short"></detail>' with self.assertRaises(SuiteValidationError): factory.app.create_suite()
def test_scheduler_module(self): factory = AppFactory() m1, m1f1 = factory.new_basic_module('open_case', 'house') factory.form_opens_case(m1f1) m2, m2f1 = factory.new_advanced_module('scheduler_module', 'house') m2f2 = factory.new_form(m2) factory.form_requires_case(m2f1, case_type='house', update={ 'foo': '/data/question1', 'bar': '/data/question2', }) factory.form_requires_case(m2f2, case_type='house', update={ 'bleep': '/data/question1', 'bloop': '/data/question2', }) self._add_scheduler_to_module(m2) self._add_scheduler_to_form(m2f1, m2, 'form1') self._add_scheduler_to_form(m2f2, m2, 'form2') self.assertCaseProperties(factory.app, 'house', [ 'foo', 'bar', 'bleep', 'bloop', # Scheduler properties: 'last_visit_date_form1', 'last_visit_number_form1', 'last_visit_date_form2', 'last_visit_number_form2', 'current_schedule_phase', ])
def test_link_to_child_module(self): factory = AppFactory(build_version='2.9.0/latest') m0, m0f0 = factory.new_basic_module('enroll child', 'child') factory.form_opens_case(m0f0) m1, m1f0 = factory.new_basic_module('child visit', 'child') factory.form_requires_case(m1f0) factory.form_opens_case(m1f0, case_type='visit', is_subcase=True) m2, m2f0 = factory.new_advanced_module('visit history', 'visit', parent_module=m1) factory.form_requires_case(m2f0, 'child') factory.form_requires_case(m2f0, 'visit', parent_case_type='child') m0f0.post_form_workflow = WORKFLOW_FORM m0f0.form_links = [ FormLink(xpath="true()", form_id=m1f0.unique_id), ] m1f0.post_form_workflow = WORKFLOW_FORM m1f0.form_links = [ FormLink(xpath="true()", form_id=m2f0.unique_id), ] self.assertXmlPartialEqual(self.get_xml('form_link_tdh'), factory.app.create_suite(), "./entry")
def test_case_list_form_parent_child_submodule_mixed(self, *args): # * Register house (case type = house, basic) # * Register house form # * Register person (case type = person, parent select = 'Register house', advanced) # * Register person form # * Update house (case type = house, case list form = 'Register house') # * Update house form # * Update person (case type = person, case list form = 'Register person form', advanced, parent module = 'Update house') # * Update person form factory = AppFactory(build_version='2.9.0') register_house_module, register_house_form = factory.new_basic_module('register_house', 'house') factory.form_opens_case(register_house_form) register_person_module, register_person_form = factory.new_basic_module('register_person', 'house') factory.form_requires_case(register_person_form, 'house') factory.form_opens_case(register_person_form, 'person', is_subcase=True) house_module, update_house_form = factory.new_advanced_module( 'update_house', 'house', case_list_form=register_house_form ) factory.form_requires_case(update_house_form) person_module, update_person_form = factory.new_basic_module( 'update_person', 'person', parent_module=house_module, case_list_form=register_person_form ) factory.form_requires_case(update_person_form, 'person', parent_case_type='house') self.assertXmlEqual(self.get_xml('case-list-form-suite-parent-child-submodule-mixed'), factory.app.create_suite())
def test_form_links_submodule(self): """ Test that when linking between two forms in a submodule we match up the session variables between the source and target form correctly :return: """ factory = AppFactory(build_version='2.9.0/latest') m0, m0f0 = factory.new_basic_module('child visit', 'child') factory.form_requires_case(m0f0) factory.form_opens_case(m0f0, 'visit', is_subcase=True) m1, m1f0 = factory.new_advanced_module('visit histroy', 'visit', parent_module=m0) factory.form_requires_case(m1f0, 'child') factory.form_requires_case(m1f0, 'visit', parent_case_type='child') m1f1 = factory.new_form(m1) factory.form_requires_case(m1f1, 'child') factory.form_requires_case(m1f1, 'visit', parent_case_type='child') m1f0.post_form_workflow = WORKFLOW_FORM m1f0.form_links = [ FormLink(xpath="true()", form_id=m1f1.unique_id), ] self.assertXmlPartialEqual(self.get_xml('form_link_submodule'), factory.app.create_suite(), "./entry")
def test_case_list_form_parent_child_advanced(self): # * Register house (case type = house, basic) # * Register house form # * Register person (case type = person, parent select = 'Register house', advanced) # * Register person form # * Manager person (case type = person, case list form = 'Register person form', basic) # * Manage person form factory = AppFactory(build_version='2.9.0') register_house_module, register_house_form = factory.new_basic_module( 'register_house', 'house') factory.form_opens_case(register_house_form) register_person_module, register_person_form = factory.new_advanced_module( 'register_person', 'person') factory.form_requires_case(register_person_form, 'house') factory.form_opens_case(register_person_form, 'person', is_subcase=True) person_module, update_person_form = factory.new_basic_module( 'update_person', 'person', case_list_form=register_person_form) person_module.parent_select.active = True person_module.parent_select.module_id = register_house_module.unique_id factory.form_requires_case(update_person_form) self.assertXmlEqual( self.get_xml('case-list-form-suite-parent-child-advanced'), factory.app.create_suite())
def setUpClass(cls): super(TestBuildingSchemaFromApplication, cls).setUpClass() cls.current_app = Application.wrap(cls.get_json('basic_application')) cls.first_build = Application.wrap(cls.get_json('basic_application')) cls.first_build._id = '123' cls.first_build.copy_of = cls.current_app.get_id cls.first_build.version = 3 cls.first_build.has_submissions = True factory = AppFactory(build_version='2.36.0') m0, f0 = factory.new_advanced_module('mod0', 'advanced') f0.source = cls.get_xml('repeat_group_form').decode('utf-8') f0.xmlns = 'repeat-xmlns' factory.form_requires_case(f0, 'case0') f0.actions.open_cases = [ AdvancedOpenCaseAction( case_type="advanced", case_tag="open_case_0", name_path="/data/question3/question4", repeat_context="/data/question3", case_indices=[CaseIndex(tag='load_case0_0')]) ] cls.advanced_app = factory.app cls.advanced_app.save() cls.apps = [ cls.current_app, cls.first_build, cls.advanced_app, ] with drop_connected_signals(app_post_save): for app in cls.apps: app.save()
def test_manual_form_link(self): factory = AppFactory(build_version='2.9.0/latest') m0, m0f0 = factory.new_basic_module('enroll child', 'child') factory.form_opens_case(m0f0) m1, m1f0 = factory.new_basic_module('child visit', 'child') factory.form_requires_case(m1f0) factory.form_opens_case(m1f0, case_type='visit', is_subcase=True) m2, m2f0 = factory.new_advanced_module('visit history', 'visit', parent_module=m1) factory.form_requires_case(m2f0, 'child') factory.form_requires_case(m2f0, 'visit', parent_case_type='child') m0f0.post_form_workflow = WORKFLOW_FORM m0f0.form_links = [ FormLink(xpath="true()", form_id=m1f0.unique_id, datums=[ FormDatum(name='case_id', xpath="instance('commcaresession')/session/data/case_id_new_child_0") ]), ] m1f0.post_form_workflow = WORKFLOW_FORM m1f0.form_links = [ FormLink(xpath="true()", form_id=m2f0.unique_id, datums=[ FormDatum(name='case_id', xpath="instance('commcaresession')/session/data/case_id"), FormDatum(name='case_id_load_visit_0', xpath="instance('commcaresession')/session/data/case_id_new_visit_0"), ]), ] self.assertXmlPartialEqual(self.get_xml('form_link_tdh'), factory.app.create_suite(), "./entry")
def test_persistent_case_name_when_tiles_enabled(self): """ Confirm that the persistent case name context is not added when case tiles are configured to persist in forms """ factory = AppFactory() module, form = factory.new_advanced_module("my_module", "person") factory.form_requires_case(form, "person") module.case_details.short.custom_xml = '<detail id="m0_case_short"></detail>' module.case_details.short.persist_tile_on_forms = True module.case_details.short.persist_case_context = True suite = factory.app.create_suite() self.assertXmlDoesNotHaveXpath(suite, "detail[@id='m0_persistent_case_context']") self.assertXmlPartialEqual( """ <partial> <datum detail-confirm="m0_case_long" detail-persistent="m0_case_short" detail-select="m0_case_short" id="case_id_load_person_0" nodeset="instance('casedb')/casedb/case[@case_type='person'][@status='open']" value="./@case_id" /> </partial> """, suite, "entry/session/datum" )
def test_case_list_form_parent_child_submodule_mixed(self): # * Register house (case type = house, basic) # * Register house form # * Register person (case type = person, parent select = 'Register house', advanced) # * Register person form # * Update house (case type = house, case list form = 'Register house') # * Update house form # * Update person (case type = person, case list form = 'Register person form', advanced, parent module = 'Update house') # * Update person form factory = AppFactory(build_version='2.9.0') register_house_module, register_house_form = factory.new_basic_module('register_house', 'house') factory.form_opens_case(register_house_form) register_person_module, register_person_form = factory.new_basic_module('register_person', 'house') factory.form_requires_case(register_person_form, 'house') factory.form_opens_case(register_person_form, 'person', is_subcase=True) house_module, update_house_form = factory.new_advanced_module( 'update_house', 'house', case_list_form=register_house_form ) factory.form_requires_case(update_house_form) person_module, update_person_form = factory.new_basic_module( 'update_person', 'person', parent_module=house_module, case_list_form=register_person_form ) factory.form_requires_case(update_person_form, 'person', parent_case_type='house') self.assertXmlEqual(self.get_xml('case-list-form-suite-parent-child-submodule-mixed'), factory.app.create_suite())
def test_persistent_case_tiles_in_advanced_module_case_lists(self): """ Test that the detail-persistent attributes is set correctly when persistent case tiles are used on advanced module case lists """ factory = AppFactory() module, form = factory.new_advanced_module("my_module", "person") factory.form_requires_case(form, "person") module.case_list.show = True module.case_details.short.custom_xml = '<detail id="m0_case_short"></detail>' module.case_details.short.persist_tile_on_forms = True suite = factory.app.create_suite() # The relevant check is really that detail-persistent="m0_case_short" # but assertXmlPartialEqual xpath implementation doesn't currently # support selecting attributes self.assertXmlPartialEqual( """ <partial> <datum detail-confirm="m0_case_long" detail-persistent="m0_case_short" detail-select="m0_case_short" id="case_id_case_person" nodeset="instance('casedb')/casedb/case[@case_type='person'][@status='open']" value="./@case_id" /> </partial> """, suite, 'entry/command[@id="m0-case-list"]/../session/datum', )
def test_case_list_form_advanced_module_different_case_config(self, *args): case_tile_error = { 'type': "all forms in case list module must load the same cases", 'module': { 'id': 1, 'name': { 'en': 'update module' } }, 'form': { 'id': 1, 'name': { 'en': 'update form 1' } }, } factory = AppFactory(build_version='2.11.0') m0, m0f0 = factory.new_basic_module('register', 'person') factory.form_opens_case(m0f0) m1, m1f0 = factory.new_advanced_module('update', 'person', case_list_form=m0f0) factory.form_requires_case(m1f0, case_type='house') factory.form_requires_case(m1f0, parent_case_type='house') m1f1 = factory.new_form(m1) factory.form_requires_case( m1f1) # only loads a person case and not a house case errors = factory.app.validate_app() self._clean_unique_id(errors) self.assertIn(case_tile_error, errors)
def test_persistent_case_name_when_tiles_enabled(self): """ Confirm that the persistent case name context is not added when case tiles are configured to persist in forms """ factory = AppFactory() module, form = factory.new_advanced_module("my_module", "person") factory.form_requires_case(form, "person") module.case_details.short.custom_xml = '<detail id="m0_case_short"></detail>' module.case_details.short.persist_tile_on_forms = True module.case_details.short.persist_case_context = True suite = factory.app.create_suite() self.assertXmlDoesNotHaveXpath( suite, "detail[@id='m0_persistent_case_context']") self.assertXmlPartialEqual( """ <partial> <datum detail-confirm="m0_case_long" detail-persistent="m0_case_short" detail-select="m0_case_short" id="case_id_load_person_0" nodeset="instance('casedb')/casedb/case[@case_type='person'][@status='open']" value="./@case_id" /> </partial> """, suite, "entry/session/datum")
def test_case_list_form_requires_parent_case_but_target_doesnt( self, *args): factory = AppFactory(build_version='2.9.0') register_household_module, register_household_form = factory.new_basic_module( 'new_household', 'household') factory.form_opens_case(register_household_form) households, edit_household_form = factory.new_basic_module( 'households', 'household', case_list_form=register_household_form) factory.form_requires_case(edit_household_form) register_member_module, register_member_form = factory.new_advanced_module( 'new_member', 'member') factory.form_requires_case(register_member_form, 'household') factory.form_opens_case(register_member_form, 'member', is_subcase=True) members, edit_member_form = factory.new_basic_module( 'members', 'member', case_list_form=register_member_form) factory.form_requires_case(edit_member_form) suite = factory.app.create_suite() self.assertXmlEqual(self.get_xml('source_requires_case_target_doesnt'), suite)
def test_case_list_form_parent_child_advanced(self): """ * Register house (case type = house, basic) * Register house form * Register person (case type = person, parent select = 'Register house', advanced) * Register person form * Manager person (case type = person, case list form = 'Register person form', basic) * Manage person form """ factory = AppFactory(build_version='2.9') register_house_module, register_house_form = factory.new_basic_module('register_house', 'house') factory.form_opens_case(register_house_form) register_person_module, register_person_form = factory.new_advanced_module('register_person', 'person') factory.form_updates_case(register_person_form, 'house') factory.form_opens_case(register_person_form, 'person', is_subcase=True) person_module, update_person_form = factory.new_basic_module( 'update_person', 'person', case_list_form=register_person_form ) person_module.parent_select.active = True person_module.parent_select.module_id = register_house_module.unique_id factory.form_updates_case(update_person_form) self.assertXmlEqual(self.get_xml('case-list-form-suite-parent-child-advanced'), factory.app.create_suite())
def test_manual_form_link(self): factory = AppFactory(build_version='2.9.0') m0, m0f0 = factory.new_basic_module('enroll child', 'child') factory.form_opens_case(m0f0) m1, m1f0 = factory.new_basic_module('child visit', 'child') factory.form_requires_case(m1f0) factory.form_opens_case(m1f0, case_type='visit', is_subcase=True) m2, m2f0 = factory.new_advanced_module('visit history', 'visit', parent_module=m1) factory.form_requires_case(m2f0, 'child') factory.form_requires_case(m2f0, 'visit', parent_case_type='child') m0f0.post_form_workflow = WORKFLOW_FORM m0f0.form_links = [ FormLink(xpath="true()", form_id=m1f0.unique_id, datums=[ FormDatum(name='case_id', xpath="instance('commcaresession')/session/data/case_id_new_child_0") ]), ] m1f0.post_form_workflow = WORKFLOW_FORM m1f0.form_links = [ FormLink(xpath="true()", form_id=m2f0.unique_id, datums=[ FormDatum(name='case_id', xpath="instance('commcaresession')/session/data/case_id"), FormDatum(name='case_id_load_visit_0', xpath="instance('commcaresession')/session/data/case_id_new_visit_0"), ]), ] self.assertXmlPartialEqual(self.get_xml('form_link_tdh'), factory.app.create_suite(), "./entry")
def test_case_list_form_parent_child_submodule_advanced_rename_case_var( self): """Test that the session vars in the entries for the submodule get updated to match the parent (and to avoid naming conflicts). m3-f0: 'case_id_load_house' -> 'case_id_load_house_renamed' m3-f0: 'case_id_load_house_renamed' -> 'case_id_load_house_renamed_person' """ factory = AppFactory(build_version='2.9') register_house_module, register_house_form = factory.new_basic_module( 'register_house', 'house') factory.form_opens_case(register_house_form) register_person_module, register_person_form = factory.new_advanced_module( 'register_person', 'person') factory.form_updates_case(register_person_form, 'house') factory.form_opens_case(register_person_form, 'person', is_subcase=True) house_module, update_house_form = factory.new_advanced_module( 'update_house', 'house', case_list_form=register_house_form) factory.form_updates_case(update_house_form) # changing this case tag should result in the session var in the submodule entry being updated to match it update_house_form.actions.load_update_cases[ 0].case_tag = 'load_house_renamed' person_module, update_person_form = factory.new_advanced_module( 'update_person', 'person', parent_module=house_module, case_list_form=register_person_form) factory.form_updates_case(update_person_form, 'house') factory.form_updates_case(update_person_form, 'person', parent_case_type='house') # making this case tag the same as the one in the parent module should mean that it will also # get changed to avoid conflicts update_person_form.actions.load_update_cases[ 1].case_tag = 'load_house_renamed' self.assertXmlEqual( self.get_xml( 'case-list-form-suite-parent-child-submodule-advanced-rename-var' ), factory.app.create_suite())
def test_case_list_registration_form_advanced_autoload(self): factory = AppFactory(build_version='2.9.0') register_module, register_form = factory.new_advanced_module( 'register_dugong', 'dugong') factory.form_opens_case(register_form) register_form.actions.load_update_cases.append( LoadUpdateAction(case_tag='usercase', auto_select=AutoSelectCase( mode=AUTO_SELECT_USERCASE, ))) case_module, update_form = factory.new_advanced_module( 'update_dugong', 'dugong') factory.form_requires_case(update_form) case_module.case_list_form.form_id = register_form.get_unique_id() case_module.case_list_form.label = {'en': 'Register another Dugong'} self.assertXmlEqual(self.get_xml('case-list-form-advanced-autoload'), factory.app.create_suite())
def test_form_rename_session_vars(self): """ The session vars in the entries for the submodule should match the parent and avoid naming conflicts. """ factory = AppFactory(build_version='2.9.0') reg_goldfish_mod, reg_goldfish_form = factory.new_basic_module( 'reg_goldfish', 'gold-fish') factory.form_opens_case(reg_goldfish_form) reg_guppy_mod, reg_guppy_form = factory.new_advanced_module( 'reg_guppy', 'guppy') factory.form_requires_case(reg_guppy_form, 'gold-fish') factory.form_opens_case(reg_guppy_form, 'guppy', is_subcase=True) upd_goldfish_mod, upd_goldfish_form = factory.new_advanced_module( 'upd_goldfish', 'gold-fish', ) factory.form_requires_case(upd_goldfish_form) # changing this case tag should result in the session var in the submodule entry being updated to match it upd_goldfish_form.actions.load_update_cases[ 0].case_tag = 'load_goldfish_renamed' upd_guppy_mod, upd_guppy_form = factory.new_advanced_module( 'upd_guppy', 'guppy', parent_module=upd_goldfish_mod, ) upd_guppy_form.source = self.get_xml( 'original_form', override_path=('data', )).decode('utf-8') factory.form_requires_case(upd_guppy_form, 'gold-fish', update={'question1': '/data/question1'}) factory.form_requires_case(upd_guppy_form, 'guppy', parent_case_type='gold-fish', update={'question1': '/data/question1'}) # making this case tag the same as the one in the parent module should mean that it will also get changed # to avoid conflicts upd_guppy_form.actions.load_update_cases[ 1].case_tag = 'load_goldfish_renamed' self.assertXmlEqual(self.get_xml('child-module-rename-session-vars'), upd_guppy_form.render_xform())
def test_case_list_registration_form_advanced_autoload(self): factory = AppFactory(build_version='2.9') register_module, register_form = factory.new_advanced_module('register_dugong', 'dugong') factory.form_opens_case(register_form) register_form.actions.load_update_cases.append(LoadUpdateAction( case_tag='usercase', auto_select=AutoSelectCase( mode=AUTO_SELECT_USERCASE, ) )) case_module, update_form = factory.new_advanced_module('update_dugong', 'dugong') factory.form_updates_case(update_form) case_module.case_list_form.form_id = register_form.get_unique_id() case_module.case_list_form.label = { 'en': 'Register another Dugong' } self.assertXmlEqual(self.get_xml('case-list-form-advanced-autoload'), factory.app.create_suite())
def test_reference_to_missing_session_variable_in_stack(self): # http://manage.dimagi.com/default.asp?236750 # # Stack create blocks do not update the session after each datum # so items put into the session in one step aren't available later steps # # <datum id="case_id_A" value="instance('commcaresession')/session/data/case_id_new_A"/> # - <datum id="case_id_B" value="instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/case_id_A]/index/host"/> # + <datum id="case_id_B" value="instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/case_id_new_A]/index/host"/> # # in the above example ``case_id_A`` is being added to the session and then # later referenced. However since the session doesn't get updated # the value isn't available in the session. # # To fix this we need to replace any references to previous variables with the full xpath which # that session variable references. # # See corehq.apps.app_manager.suite_xml.post_process.workflow._replace_session_references_in_stack factory = AppFactory(build_version='2.9.0/latest') m0, m0f0 = factory.new_basic_module('person registration', 'person') factory.form_opens_case(m0f0) m1, m1f0 = factory.new_advanced_module('episode registration', 'episode') factory.form_requires_case(m1f0, case_type='person') factory.form_opens_case(m1f0, case_type='episode', is_subcase=True, is_extension=True) m2, m2f0 = factory.new_advanced_module('tests', 'episode') factory.form_requires_case(m2f0, 'episode') factory.advanced_form_autoloads(m2f0, AUTO_SELECT_CASE, 'host', 'load_episode_0') m1f0.post_form_workflow = WORKFLOW_FORM m1f0.form_links = [ FormLink(xpath="true()", form_id=m2f0.unique_id, datums=[ FormDatum(name='case_id_load_episode_0', xpath="instance('commcaresession')/session/data/case_id_new_episode_0") ]), ] self.assertXmlPartialEqual(self.get_xml('form_link_enikshay'), factory.app.create_suite(), "./entry")
def test_incorrect_case_var_for_case_update(self): # see http://manage.dimagi.com/default.asp?230013 factory = AppFactory(build_version='2.9.0') new_episode_module, new_episode_form = factory.new_basic_module('register_episode', 'episode') factory.form_opens_case(new_episode_form) lab_test_module, lab_test_form = factory.new_advanced_module('lab_test', 'episode') factory.form_requires_case(lab_test_form, 'episode') factory.form_opens_case(lab_test_form, 'lab_test', is_subcase=True, is_extension=True) factory.form_opens_case(lab_test_form, 'lab_referral', is_subcase=True, parent_tag='open_lab_test') lab_update_module, lab_update_form = factory.new_advanced_module('lab_update', 'lab_test', parent_module=lab_test_module) factory.form_requires_case(lab_update_form, 'episode', update={'episode_type': '/data/question1'}) factory.form_requires_case(lab_update_form, 'lab_test', parent_case_type='episode') lab_update_form.source = self.get_xml('original_form', override_path=('data',)).decode('utf-8') expected_suite_entry = """ <partial> <session> <datum id="case_id_load_episode_0" nodeset="instance('casedb')/casedb/case[@case_type='episode'][@status='open']" value="./@case_id" detail-select="m0_case_short"/> <datum id="case_id_new_lab_test_0" function="uuid()"/> <datum id="case_id_new_lab_referral_1" function="uuid()"/> <datum id="case_id_load_lab_test_0" nodeset="instance('casedb')/casedb/case[@case_type='lab_test'][@status='open'][index/parent=instance('commcaresession')/session/data/case_id_load_episode_0]" value="./@case_id" detail-select="m2_case_short" detail-confirm="m2_case_long"/> </session> </partial>""" suite_xml = factory.app.create_suite() self.assertXmlPartialEqual( expected_suite_entry, suite_xml, './entry[3]/session' ) form_xml = lab_update_form.render_xform().decode('utf-8') self.assertTrue( '<bind calculate="instance(\'commcaresession\')/session/data/case_id_new_lab_test_0" nodeset="/data/case_load_episode_0/case/@case_id"/>' not in form_xml ) self.assertTrue( '<bind calculate="instance(\'commcaresession\')/session/data/case_id_load_episode_0" nodeset="/data/case_load_episode_0/case/@case_id"/>' in form_xml )
def test_case_list_form_parent_child_submodule_advanced_rename_case_var(self): """Test that the session vars in the entries for the submodule get updated to match the parent (and to avoid naming conflicts). m3-f0: 'case_id_load_house' -> 'case_id_load_house_renamed' m3-f0: 'case_id_load_house_renamed' -> 'case_id_load_house_renamed_person' """ factory = AppFactory(build_version='2.9') register_house_module, register_house_form = factory.new_basic_module('register_house', 'house') factory.form_opens_case(register_house_form) register_person_module, register_person_form = factory.new_advanced_module('register_person', 'person') factory.form_updates_case(register_person_form, 'house') factory.form_opens_case(register_person_form, 'person', is_subcase=True) house_module, update_house_form = factory.new_advanced_module( 'update_house', 'house', case_list_form=register_house_form ) factory.form_updates_case(update_house_form) # changing this case tag should result in the session var in the submodule entry being updated to match it update_house_form.actions.load_update_cases[0].case_tag = 'load_house_renamed' person_module, update_person_form = factory.new_advanced_module( 'update_person', 'person', parent_module=house_module, case_list_form=register_person_form ) factory.form_updates_case(update_person_form, 'house') factory.form_updates_case(update_person_form, 'person', parent_case_type='house') # making this case tag the same as the one in the parent module should mean that it will also # get changed to avoid conflicts update_person_form.actions.load_update_cases[1].case_tag = 'load_house_renamed' self.assertXmlEqual(self.get_xml('case-list-form-suite-parent-child-submodule-advanced-rename-var'), factory.app.create_suite())
def test_empty_module_errors(self): factory = AppFactory(build_version='2.24') app = factory.app m1 = factory.new_basic_module('register', 'case', with_form=False) factory.new_advanced_module('update', 'case', with_form=False) m2 = factory.new_basic_module('update', 'case', with_form=False) m2.case_list = CaseList(show=True, label={'en': "case_list"}) factory.new_shadow_module('update', m1, with_form=False) errors = app.validate_app() standard_module_error = { 'type': 'no forms or case list', 'module': {'id': 0, 'name': {'en': u'register module'}}, } advanced_module_error = { 'type': 'no forms or case list', 'module': {'id': 1, 'name': {'en': u'update module'}}, } self.assertEqual(len(errors), 2) self.assertIn(standard_module_error, errors) self.assertIn(advanced_module_error, errors)
def test_form_rename_session_vars(self): """ The session vars in the entries for the submodule should match the parent and avoid naming conflicts. """ factory = AppFactory(build_version='2.9.0') reg_goldfish_mod, reg_goldfish_form = factory.new_basic_module('reg_goldfish', 'gold-fish') factory.form_opens_case(reg_goldfish_form) reg_guppy_mod, reg_guppy_form = factory.new_advanced_module('reg_guppy', 'guppy') factory.form_requires_case(reg_guppy_form, 'gold-fish') factory.form_opens_case(reg_guppy_form, 'guppy', is_subcase=True) upd_goldfish_mod, upd_goldfish_form = factory.new_advanced_module( 'upd_goldfish', 'gold-fish', ) factory.form_requires_case(upd_goldfish_form) # changing this case tag should result in the session var in the submodule entry being updated to match it upd_goldfish_form.actions.load_update_cases[0].case_tag = 'load_goldfish_renamed' upd_guppy_mod, upd_guppy_form = factory.new_advanced_module( 'upd_guppy', 'guppy', parent_module=upd_goldfish_mod, ) upd_guppy_form.source = self.get_xml('original_form', override_path=('data',)).decode('utf-8') factory.form_requires_case(upd_guppy_form, 'gold-fish', update={'question1': '/data/question1'}) factory.form_requires_case( upd_guppy_form, 'guppy', parent_case_type='gold-fish', update={'question1': '/data/question1'} ) # making this case tag the same as the one in the parent module should mean that it will also get changed # to avoid conflicts upd_guppy_form.actions.load_update_cases[1].case_tag = 'load_goldfish_renamed' self.assertXmlEqual(self.get_xml('child-module-rename-session-vars'), upd_guppy_form.render_xform())
def _build_workflow_app(self, mode): factory = AppFactory(build_version='2.9.0') m0, m0f0 = factory.new_basic_module('m0', '') factory.new_form(m0) m1, m1f0 = factory.new_basic_module('m1', 'patient') m1f1 = factory.new_form(m1) factory.form_opens_case(m1f0) factory.form_requires_case(m1f1) m2, m2f0 = factory.new_basic_module('m2', 'patient') m2f1 = factory.new_form(m2) factory.form_requires_case(m2f0) factory.form_requires_case(m2f1) m3, m3f0 = factory.new_basic_module('m3', 'child') m3f1 = factory.new_form(m3) factory.form_requires_case(m3f0, parent_case_type='patient') factory.form_requires_case(m3f1) m4, m4f0 = factory.new_advanced_module('m4', 'patient') factory.form_requires_case(m4f0, case_type='patient') factory.form_requires_case(m4f0, case_type='patient') m4f1 = factory.new_form(m4) factory.form_requires_case(m4f1, case_type='patient') factory.form_requires_case(m4f1, case_type='patient') factory.form_requires_case(m4f1, case_type='patient') m4f2 = factory.new_form(m4) factory.form_requires_case(m4f2, case_type='patient') factory.form_requires_case(m4f2, case_type='patient') factory.advanced_form_autoloads(m4f2, AUTO_SELECT_RAW, 'case_id') m5, m5f0 = factory.new_basic_module('m5', 'patient', parent_module=m1) factory.form_requires_case(m5f0) m6 = factory.new_shadow_module('shadow_module', m1, with_form=False) factory.new_shadow_module('shadow_child', m5, with_form=False, parent_module=m6) for module in factory.app.get_modules(): for form in module.get_forms(): form.post_form_workflow = mode return factory.app
def test_link_to_form_in_parent_module(self): factory = AppFactory(build_version="2.9.0/latest") m0, m0f0 = factory.new_basic_module("enroll child", "child") factory.form_opens_case(m0f0) m1, m1f0 = factory.new_basic_module("child visit", "child") factory.form_updates_case(m1f0) m2, m2f0 = factory.new_advanced_module("visit history", "visit", parent_module=m1) factory.form_updates_case(m2f0, "child") # link to child -> edit child m2f0.post_form_workflow = WORKFLOW_FORM m2f0.form_links = [FormLink(xpath="true()", form_id=m1f0.unique_id)] self.assertXmlPartialEqual(self.get_xml("form_link_child_modules"), factory.app.create_suite(), "./entry[3]")
def test_manual_form_link_with_fallback(self): factory = AppFactory(build_version='2.9.0') m0, m0f0 = factory.new_basic_module('enroll child', 'child') factory.form_opens_case(m0f0) m1, m1f0 = factory.new_basic_module('child visit', 'child') factory.form_requires_case(m1f0) factory.form_opens_case(m1f0, case_type='visit', is_subcase=True) m2, m2f0 = factory.new_advanced_module('visit history', 'visit', parent_module=m1) factory.form_requires_case(m2f0, 'child') factory.form_requires_case(m2f0, 'visit', parent_case_type='child') m0f0.post_form_workflow = WORKFLOW_FORM m0f0.form_links = [ FormLink(xpath="true()", form_id=m1f0.unique_id, datums=[ FormDatum(name='case_id', xpath="instance('commcaresession')/session/data/case_id_new_child_0") ]), ] m1f0.post_form_workflow = WORKFLOW_FORM condition_for_xpath = "instance('casedb')/casedb/case[@case_id = " \ "instance('commcaresession')/session/data/case_id]/prop = 'value'" m1f0.form_links = [ FormLink(xpath="true()", form_id=m2f0.unique_id, datums=[ FormDatum(name='case_id', xpath="instance('commcaresession')/session/data/case_id"), FormDatum(name='case_id_load_visit_0', xpath="instance('commcaresession')/session/data/case_id_new_visit_0"), ]), FormLink(xpath=condition_for_xpath, form_id=m2f0.unique_id, datums=[ FormDatum(name='case_id', xpath="instance('commcaresession')/session/data/case_id"), FormDatum(name='case_id_load_visit_0', xpath="instance('commcaresession')/session/data/case_id_new_visit_0"), ]), ] m1f0.post_form_workflow_fallback = WORKFLOW_PREVIOUS self.assertXmlPartialEqual(self.get_xml('form_link_tdh_with_fallback_previous'), factory.app.create_suite(), "./entry") m1f0.post_form_workflow_fallback = WORKFLOW_MODULE self.assertXmlPartialEqual(self.get_xml('form_link_tdh_with_fallback_module'), factory.app.create_suite(), "./entry") m1f0.post_form_workflow_fallback = WORKFLOW_ROOT self.assertXmlPartialEqual(self.get_xml('form_link_tdh_with_fallback_root'), factory.app.create_suite(), "./entry")
def test_manual_form_link_with_fallback(self): factory = AppFactory(build_version='2.9.0/latest') m0, m0f0 = factory.new_basic_module('enroll child', 'child') factory.form_opens_case(m0f0) m1, m1f0 = factory.new_basic_module('child visit', 'child') factory.form_requires_case(m1f0) factory.form_opens_case(m1f0, case_type='visit', is_subcase=True) m2, m2f0 = factory.new_advanced_module('visit history', 'visit', parent_module=m1) factory.form_requires_case(m2f0, 'child') factory.form_requires_case(m2f0, 'visit', parent_case_type='child') m0f0.post_form_workflow = WORKFLOW_FORM m0f0.form_links = [ FormLink(xpath="true()", form_id=m1f0.unique_id, datums=[ FormDatum(name='case_id', xpath="instance('commcaresession')/session/data/case_id_new_child_0") ]), ] m1f0.post_form_workflow = WORKFLOW_FORM condition_for_xpath = "instance('casedb')/casedb/case[@case_id = " \ "instance('commcaresession')/session/data/case_id]/prop = 'value'" m1f0.form_links = [ FormLink(xpath="true()", form_id=m2f0.unique_id, datums=[ FormDatum(name='case_id', xpath="instance('commcaresession')/session/data/case_id"), FormDatum(name='case_id_load_visit_0', xpath="instance('commcaresession')/session/data/case_id_new_visit_0"), ]), FormLink(xpath=condition_for_xpath, form_id=m2f0.unique_id, datums=[ FormDatum(name='case_id', xpath="instance('commcaresession')/session/data/case_id"), FormDatum(name='case_id_load_visit_0', xpath="instance('commcaresession')/session/data/case_id_new_visit_0"), ]), ] m1f0.post_form_workflow_fallback = WORKFLOW_PREVIOUS self.assertXmlPartialEqual(self.get_xml('form_link_tdh_with_fallback_previous'), factory.app.create_suite(), "./entry") m1f0.post_form_workflow_fallback = WORKFLOW_MODULE self.assertXmlPartialEqual(self.get_xml('form_link_tdh_with_fallback_module'), factory.app.create_suite(), "./entry") m1f0.post_form_workflow_fallback = WORKFLOW_ROOT self.assertXmlPartialEqual(self.get_xml('form_link_tdh_with_fallback_root'), factory.app.create_suite(), "./entry")
def test_tiered_select_with_advanced_module_as_parent_with_filters(self): factory = AppFactory(build_version="2.25") parent_module, parent_form = factory.new_advanced_module("parent", "parent") parent_module.case_details.short.filter = "parent_filter = 1" child_module, child_form = factory.new_basic_module("child", "child") child_form.xmlns = "http://id_m1-f0" child_module.case_details.short.filter = "child_filter = 1" factory.form_requires_case(child_form) # make child module point to advanced module as parent child_module.parent_select.active = True child_module.parent_select.module_id = parent_module.unique_id self.assertXmlPartialEqual( self.get_xml("advanced_module_parent_filters"), factory.app.create_suite(), "./entry[2]" )
def test_tiered_select_with_advanced_module_as_parent_with_filters(self): factory = AppFactory(build_version='2.25') parent_module, parent_form = factory.new_advanced_module( 'parent', 'parent') parent_module.case_details.short.filter = 'parent_filter = 1' child_module, child_form = factory.new_basic_module('child', 'child') child_form.xmlns = 'http://id_m1-f0' child_module.case_details.short.filter = 'child_filter = 1' factory.form_requires_case(child_form) # make child module point to advanced module as parent child_module.parent_select.active = True child_module.parent_select.module_id = parent_module.unique_id self.assertXmlPartialEqual( self.get_xml('advanced_module_parent_filters'), factory.app.create_suite(), "./entry[2]")
def test_link_to_form_in_parent_module(self): factory = AppFactory(build_version='2.9.0/latest') m0, m0f0 = factory.new_basic_module('enroll child', 'child') factory.form_opens_case(m0f0) m1, m1f0 = factory.new_basic_module('child visit', 'child') factory.form_requires_case(m1f0) m2, m2f0 = factory.new_advanced_module('visit history', 'visit', parent_module=m1) factory.form_requires_case(m2f0, 'child') # link to child -> edit child m2f0.post_form_workflow = WORKFLOW_FORM m2f0.form_links = [ FormLink(xpath="true()", form_id=m1f0.unique_id), ] self.assertXmlPartialEqual(self.get_xml('form_link_child_modules'), factory.app.create_suite(), "./entry[3]")
def test_tiered_select_with_advanced_module_as_parent_with_filters(self): factory = AppFactory(build_version='2.25.0') parent_module, parent_form = factory.new_advanced_module('parent', 'parent') parent_module.case_details.short.filter = 'parent_filter = 1' child_module, child_form = factory.new_basic_module('child', 'child') child_form.xmlns = 'http://id_m1-f0' child_module.case_details.short.filter = 'child_filter = 1' factory.form_requires_case(child_form) # make child module point to advanced module as parent child_module.parent_select.active = True child_module.parent_select.module_id = parent_module.unique_id self.assertXmlPartialEqual( self.get_xml('advanced_module_parent_filters'), factory.app.create_suite(), "./entry[2]" )
def test_case_list_form_advanced_module_different_case_config(self): case_tile_error = { 'type': "all forms in case list module must load the same cases", 'module': {'id': 1, 'name': {u'en': u'update module'}}, 'form': {'id': 1, 'name': {u'en': u'update form 1'}}, } factory = AppFactory(build_version='2.11') m0, m0f0 = factory.new_basic_module('register', 'person') factory.form_opens_case(m0f0) m1, m1f0 = factory.new_advanced_module('update', 'person', case_list_form=m0f0) factory.form_requires_case(m1f0, case_type='house') factory.form_requires_case(m1f0, parent_case_type='house') m1f1 = factory.new_form(m1) factory.form_requires_case(m1f1) # only loads a person case and not a house case errors = factory.app.validate_app() self.assertIn(case_tile_error, errors)
def test_link_to_form_in_parent_module(self, *args): factory = AppFactory(build_version='2.9.0') m0, m0f0 = factory.new_basic_module('enroll child', 'child') factory.form_opens_case(m0f0) m1, m1f0 = factory.new_basic_module('child visit', 'child') factory.form_requires_case(m1f0) m2, m2f0 = factory.new_advanced_module('visit history', 'visit', parent_module=m1) factory.form_requires_case(m2f0, 'child') # link to child -> edit child m2f0.post_form_workflow = WORKFLOW_FORM m2f0.form_links = [ FormLink(xpath="true()", form_id=m1f0.unique_id), ] self.assertXmlPartialEqual(self.get_xml('form_link_child_modules'), factory.app.create_suite(), "./entry[3]")
def test_case_list_form_requires_parent_case_but_target_doesnt(self): factory = AppFactory(build_version='2.9.0') register_household_module, register_household_form = factory.new_basic_module('new_household', 'household') factory.form_opens_case(register_household_form) households, edit_household_form = factory.new_basic_module('households', 'household', case_list_form=register_household_form) factory.form_requires_case(edit_household_form) register_member_module, register_member_form = factory.new_advanced_module('new_member', 'member') factory.form_requires_case(register_member_form, 'household') factory.form_opens_case(register_member_form, 'member', is_subcase=True) members, edit_member_form = factory.new_basic_module('members', 'member', case_list_form=register_member_form) factory.form_requires_case(edit_member_form) suite = factory.app.create_suite() self.assertXmlEqual( self.get_xml('source_requires_case_target_doesnt'), suite )
def _build_workflow_app(self, mode): factory = AppFactory(build_version="2.9.0/latest") m0, m0f0 = factory.new_basic_module("m0", "") factory.new_form(m0) m1, m1f0 = factory.new_basic_module("m1", "patient") m1f1 = factory.new_form(m1) factory.form_opens_case(m1f0) factory.form_updates_case(m1f1) m2, m2f0 = factory.new_basic_module("m2", "patient") m2f1 = factory.new_form(m2) factory.form_updates_case(m2f0) factory.form_updates_case(m2f1) m3, m3f0 = factory.new_basic_module("m3", "child") m3f1 = factory.new_form(m3) factory.form_updates_case(m3f0, parent_case_type="patient") factory.form_updates_case(m3f1) m4, m4f0 = factory.new_advanced_module("m4", "patient") factory.form_updates_case(m4f0, case_type="patient") factory.form_updates_case(m4f0, case_type="patient") m4f1 = factory.new_form(m4) factory.form_updates_case(m4f1, case_type="patient") factory.form_updates_case(m4f1, case_type="patient") factory.form_updates_case(m4f1, case_type="patient") m4f2 = factory.new_form(m4) factory.form_updates_case(m4f2, case_type="patient") factory.form_updates_case(m4f2, case_type="patient") factory.advanced_form_autoloads(m4f2, AUTO_SELECT_RAW, "case_id") for module in factory.app.get_modules(): for form in module.get_forms(): form.post_form_workflow = mode return factory.app
def _build_workflow_app(self, mode): factory = AppFactory(build_version='2.9.0/latest') m0, m0f0 = factory.new_basic_module('m0', '') factory.new_form(m0) m1, m1f0 = factory.new_basic_module('m1', 'patient') m1f1 = factory.new_form(m1) factory.form_opens_case(m1f0) factory.form_requires_case(m1f1) m2, m2f0 = factory.new_basic_module('m2', 'patient') m2f1 = factory.new_form(m2) factory.form_requires_case(m2f0) factory.form_requires_case(m2f1) m3, m3f0 = factory.new_basic_module('m3', 'child') m3f1 = factory.new_form(m3) factory.form_requires_case(m3f0, parent_case_type='patient') factory.form_requires_case(m3f1) m4, m4f0 = factory.new_advanced_module('m4', 'patient') factory.form_requires_case(m4f0, case_type='patient') factory.form_requires_case(m4f0, case_type='patient') m4f1 = factory.new_form(m4) factory.form_requires_case(m4f1, case_type='patient') factory.form_requires_case(m4f1, case_type='patient') factory.form_requires_case(m4f1, case_type='patient') m4f2 = factory.new_form(m4) factory.form_requires_case(m4f2, case_type='patient') factory.form_requires_case(m4f2, case_type='patient') factory.advanced_form_autoloads(m4f2, AUTO_SELECT_RAW, 'case_id') for module in factory.app.get_modules(): for form in module.get_forms(): form.post_form_workflow = mode return factory.app
def setUpClass(cls): super(TestBuildingSchemaFromApplication, cls).setUpClass() cls.current_app = Application.wrap(cls.get_json('basic_application')) cls.first_build = Application.wrap(cls.get_json('basic_application')) cls.first_build._id = '123' cls.first_build.copy_of = cls.current_app.get_id cls.first_build.version = 3 cls.first_build.has_submissions = True factory = AppFactory(build_version='2.36.0') m0, f0 = factory.new_advanced_module('mod0', 'advanced') f0.source = cls.get_xml('repeat_group_form').decode('utf-8') f0.xmlns = 'repeat-xmlns' factory.form_requires_case(f0, 'case0') f0.actions.open_cases = [ AdvancedOpenCaseAction( case_type="advanced", case_tag="open_case_0", name_path="/data/question3/question4", repeat_context="/data/question3", case_indices=[CaseIndex(tag='load_case0_0')] ) ] cls.advanced_app = factory.app cls.advanced_app.save() cls.apps = [ cls.current_app, cls.first_build, cls.advanced_app, ] with drop_connected_signals(app_post_save): for app in cls.apps: app.save()
def test_case_list_form_followup_form(self, *args): # * Register house (case type = house, basic) # * Register house form # * Register person (case type = person, parent select = 'Register house', advanced) # * Register person form # * Manager person (case type = person, case list form = 'Register person form', basic) # * Manage person form factory = AppFactory(build_version='2.9.0') register_house_module, register_house_form = factory.new_basic_module( 'register_house', 'house') factory.form_opens_case(register_house_form) register_person_module, register_person_form = factory.new_advanced_module( 'register_person', 'person') factory.form_requires_case(register_person_form, 'house') factory.form_opens_case(register_person_form, 'person', is_subcase=True) house_module, update_house_form = factory.new_advanced_module( 'update_house', 'house', ) factory.form_requires_case(update_house_form) person_module, update_person_form = factory.new_basic_module( 'update_person', 'person', case_list_form=update_house_form) factory.form_requires_case(update_person_form) def _assert_app_build_error(error): errors = factory.app.validate_app() self.assertIn( (error, person_module.unique_id), [(e["type"], e.get("module", {}).get("unique_id", {})) for e in errors]) self.assertXmlPartialEqual("<partial></partial>", factory.app.create_suite(), "./detail[@id='m3_case_short']/action") # should fail since feature flag isn't enabled _assert_app_build_error('case list form not registration') with flag_enabled('FOLLOWUP_FORMS_AS_CASE_LIST_FORM'): # should fail since module doesn't have active parent_select _assert_app_build_error("invalid case list followup form") person_module.parent_select.active = True person_module.parent_select.module_id = register_house_module.unique_id person_module.case_list_form.relevancy_expression = "count(instance('casedb')/casedb/case) != 0" errors = factory.app.validate_app() self.assertNotIn( ('case list form not registration', person_module.unique_id), [(e["type"], e.get("module", {}).get("unique_id", {})) for e in errors]) xml = """ <partial> <action relevant="count(instance('casedb')/casedb/case) != 0"> <display> <text><locale id="case_list_form.m3"/></text> </display> <stack> <push> <command value="'m2-f0'"/> <datum id="case_id_load_house_0" value="instance('commcaresession')/session/data/parent_id"/> <datum id="return_to" value="'m3'"/> </push> </stack> </action> </partial> """ self.assertXmlPartialEqual(xml, factory.app.create_suite(), "./detail[@id='m3_case_short']/action") person_module.parent_select.active = False
class ShadowFormSuiteTest(SimpleTestCase, TestXmlMixin): def setUp(self): self.factory = AppFactory() self.advanced_module, self.form0 = self.factory.new_advanced_module( 'advanced_module', 'patient') self.form0.xmlns = 'http://openrosa.org/formdesigner/firstform' self.form0.actions.open_cases = [ AdvancedOpenCaseAction( case_type="patient", case_tag="open__0", ) ] self.form0.actions.load_update_cases = [ LoadUpdateAction( case_type="patient", case_tag="load_0", case_properties={ "name": ConditionalCaseUpdate(question_path="/data/name") }, preload={"/data/name": "name"}, details_module=self.advanced_module.unique_id, ) ] self.shadow_form = self.factory.new_shadow_form(self.advanced_module) self.shadow_form.shadow_parent_form_id = self.form0.unique_id # Shadow form load_update_case actions should contain all case tags from the parent self.shadow_form.extra_actions.load_update_cases = [ LoadUpdateAction( case_type="patient", case_tag="load_0", details_module=self.advanced_module.unique_id, ) ] self.basic_module = self.factory.new_basic_module("basic_module", "doctor", with_form=False) def test_resource_not_added(self, *args): # Confirm that shadow forms do not add a <resource> node to the suite file suite = self.factory.app.create_suite() xpath = "./xform" # Note that the advanced_module only has one form, because the shadow form does not contribute an xform expected = """ <partial> <xform> <resource id="advanced_module_form_0"> <location authority="local">./modules-0/forms-0.xml</location> <location authority="remote">./modules-0/forms-0.xml</location> </resource> </xform> </partial> """ self.assertXmlPartialEqual(expected, suite, xpath) def test_shadow_form_session_matches_parent(self, *args): # Confirm that shadow form session matches shadow parent session. # This confirms that the parent load actions are properly transfered to the shadow form suite = self.factory.app.create_suite() shadow_source_session = extract_xml_partial( suite, "./entry/command[@id='m0-f0']/../session") shadow_form_session = extract_xml_partial( suite, "./entry/command[@id='m0-f1']/../session") self.assertXMLEqual(shadow_source_session.decode('utf-8'), shadow_form_session.decode('utf-8')) def test_shadow_form_entry_references_source_form(self, *args): suite = self.factory.app.create_suite() xpath = "./entry/command[@id='m0-f1']/../form" expected = """ <partial> <form>{}</form> </partial> """.format(self.form0.xmlns) self.assertXmlPartialEqual(expected, suite, xpath) def test_shadow_form_action_additions(self, *args): # Confirm that shadow form action additions are reflected in the suite file original_actions = self.shadow_form.extra_actions.load_update_cases try: self.shadow_form.extra_actions.load_update_cases = [ LoadUpdateAction( case_type="patient", case_tag="load_0", details_module=self.advanced_module.unique_id, ), LoadUpdateAction(case_tag="load_1", case_type="doctor", details_module=self.basic_module.unique_id) ] suite = self.factory.app.create_suite() finally: # reset the actions self.shadow_form.extra_actions.load_update_cases = original_actions # Confirm that the source session has not changed: expected_source_session = """ <partial> <session> <datum detail-confirm="m0_case_long" detail-select="m0_case_short" id="case_id_load_0" nodeset="instance('casedb')/casedb/case[@case_type='patient'][@status='open']" value="./@case_id" /> <datum function="uuid()" id="case_id_new_patient_0"/> </session> </partial> """ self.assertXmlPartialEqual(expected_source_session, suite, "./entry/command[@id='m0-f0']/../session") # Confirm that the shadow session HAS changed: expected_shadow_session = """ <partial> <session> <datum detail-confirm="m0_case_long" detail-select="m0_case_short" id="case_id_load_0" nodeset="instance('casedb')/casedb/case[@case_type='patient'][@status='open']" value="./@case_id" /> <datum detail-confirm="m1_case_long" detail-select="m1_case_short" id="case_id_load_1" nodeset="instance('casedb')/casedb/case[@case_type='doctor'][@status='open']" value="./@case_id" /> <datum function="uuid()" id="case_id_new_patient_0"/> </session> </partial> """ self.assertXmlPartialEqual(expected_shadow_session, suite, "./entry/command[@id='m0-f1']/../session") def test_shadow_form_action_modifications(self, *args): # Confirm that shadow form action modifications are reflected in the suite file original_actions = self.shadow_form.extra_actions.load_update_cases try: self.shadow_form.extra_actions.load_update_cases = [ LoadUpdateAction(case_tag="load_0", case_type="doctor", details_module=self.basic_module.unique_id) ] suite = self.factory.app.create_suite() finally: # reset the actions self.shadow_form.extra_actions.load_update_cases = original_actions # Confirm that the source session has not changed: expected_source_session = """ <partial> <session> <datum detail-confirm="m0_case_long" detail-select="m0_case_short" id="case_id_load_0" nodeset="instance('casedb')/casedb/case[@case_type='patient'][@status='open']" value="./@case_id" /> <datum function="uuid()" id="case_id_new_patient_0"/> </session> </partial> """ self.assertXmlPartialEqual(expected_source_session, suite, "./entry/command[@id='m0-f0']/../session") # Confirm that the shadow session HAS changed: expected_shadow_session = """ <partial> <session> <datum detail-confirm="m1_case_long" detail-select="m1_case_short" id="case_id_load_0" nodeset="instance('casedb')/casedb/case[@case_type='doctor'][@status='open']" value="./@case_id" /> <datum function="uuid()" id="case_id_new_patient_0"/> </session> </partial> """ self.assertXmlPartialEqual(expected_shadow_session, suite, "./entry/command[@id='m0-f1']/../session") def test_shadow_form_action_reordering(self, *args): # Confirm that the ordering of the actions in the shadow form is used, not the source ordering source_form_original_actions = self.form0.actions.load_update_cases shadow_form_original_actions = self.shadow_form.extra_actions.load_update_cases try: # Add an action to the source form self.form0.actions.load_update_cases = [ LoadUpdateAction( case_type="patient", case_tag="load_0", case_properties={ "name": ConditionalCaseUpdate(question_path="/data/name") }, preload={"/data/name": "name"}, details_module=self.advanced_module.unique_id, ), LoadUpdateAction( case_type="patient", case_tag="load_1", case_properties={ "name": ConditionalCaseUpdate(question_path="/data/name") }, preload={"/data/name": "name"}, details_module=self.advanced_module.unique_id, ) ] # specify a different order in the shadow form self.shadow_form.extra_actions.load_update_cases = [ LoadUpdateAction( case_tag="load_1", case_type="patient", details_module=self.advanced_module.unique_id, ), LoadUpdateAction( case_tag="load_0", case_type="patient", details_module=self.advanced_module.unique_id, ) ] suite = self.factory.app.create_suite() finally: # reset the actions self.form0.actions.load_update_cases = source_form_original_actions self.shadow_form.extra_actions.load_update_cases = shadow_form_original_actions # Confirm that the load_0 action comes first in the source form self.assertXmlHasXpath( suite, "./entry/command[@id='m0-f0']/../session/datum[@id='case_id_load_0' and position() = 1]" ) self.assertXmlHasXpath( suite, "./entry/command[@id='m0-f0']/../session/datum[@id='case_id_load_1' and position() = 2]" ) # Confirm that the load_0 action comes second in the shadow form self.assertXmlHasXpath( suite, "./entry/command[@id='m0-f1']/../session/datum[@id='case_id_load_1' and position() = 1]" ) self.assertXmlHasXpath( suite, "./entry/command[@id='m0-f1']/../session/datum[@id='case_id_load_0' and position() = 2]" )
class ShadowFormSuiteTest(SimpleTestCase, TestXmlMixin): def setUp(self): self.factory = AppFactory() self.advanced_module, self.form0 = self.factory.new_advanced_module('advanced_module', 'patient') self.form0.xmlns = 'http://openrosa.org/formdesigner/firstform' self.form0.actions.open_cases = [ AdvancedOpenCaseAction( case_type="patient", case_tag="open__0", ) ] self.form0.actions.load_update_cases = [ LoadUpdateAction( case_type="patient", case_tag="load_0", case_properties={ "name": "/data/name" }, preload={ "/data/name": "name" }, details_module=self.advanced_module.unique_id, ) ] self.shadow_form = self.factory.new_shadow_form(self.advanced_module) self.shadow_form.shadow_parent_form_id = self.form0.unique_id # Shadow form load_update_case actions should contain all case tags from the parent self.shadow_form.extra_actions.load_update_cases = [ LoadUpdateAction( case_type="patient", case_tag="load_0", details_module=self.advanced_module.unique_id, ) ] self.basic_module = self.factory.new_basic_module("basic_module", "doctor", with_form=False) def test_resource_not_added(self): # Confirm that shadow forms do not add a <resource> node to the suite file suite = self.factory.app.create_suite() xpath = "./xform" # Note that the advanced_module only has one form, because the shadow form does not contribute an xform expected = """ <partial> <xform> <resource id="advanced_module_form_0"> <location authority="local">./modules-0/forms-0.xml</location> <location authority="remote">./modules-0/forms-0.xml</location> </resource> </xform> </partial> """ self.assertXmlPartialEqual(expected, suite, xpath) def test_shadow_form_session_matches_parent(self): # Confirm that shadow form session matches shadow parent session. # This confirms that the parent load actions are properly transfered to the shadow form suite = self.factory.app.create_suite() shadow_source_session = extract_xml_partial(suite, "./entry/command[@id='m0-f0']/../session") shadow_form_session = extract_xml_partial(suite, "./entry/command[@id='m0-f1']/../session") self.assertXMLEqual(shadow_source_session.decode('utf-8'), shadow_form_session.decode('utf-8')) def test_shadow_form_entry_references_source_form(self): suite = self.factory.app.create_suite() xpath = "./entry/command[@id='m0-f1']/../form" expected = """ <partial> <form>{}</form> </partial> """.format(self.form0.xmlns) self.assertXmlPartialEqual(expected, suite, xpath) def test_shadow_form_action_additions(self): # Confirm that shadow form action additions are reflected in the suite file original_actions = self.shadow_form.extra_actions.load_update_cases try: self.shadow_form.extra_actions.load_update_cases = [ LoadUpdateAction( case_type="patient", case_tag="load_0", details_module=self.advanced_module.unique_id, ), LoadUpdateAction( case_tag="load_1", case_type="doctor", details_module=self.basic_module.unique_id ) ] suite = self.factory.app.create_suite() finally: # reset the actions self.shadow_form.extra_actions.load_update_cases = original_actions # Confirm that the source session has not changed: expected_source_session = """ <partial> <session> <datum detail-confirm="m0_case_long" detail-select="m0_case_short" id="case_id_load_0" nodeset="instance('casedb')/casedb/case[@case_type='patient'][@status='open']" value="./@case_id" /> <datum function="uuid()" id="case_id_new_patient_0"/> </session> </partial> """ self.assertXmlPartialEqual(expected_source_session, suite, "./entry/command[@id='m0-f0']/../session") # Confirm that the shadow session HAS changed: expected_shadow_session = """ <partial> <session> <datum detail-confirm="m0_case_long" detail-select="m0_case_short" id="case_id_load_0" nodeset="instance('casedb')/casedb/case[@case_type='patient'][@status='open']" value="./@case_id" /> <datum detail-confirm="m1_case_long" detail-select="m1_case_short" id="case_id_load_1" nodeset="instance('casedb')/casedb/case[@case_type='doctor'][@status='open']" value="./@case_id" /> <datum function="uuid()" id="case_id_new_patient_0"/> </session> </partial> """ self.assertXmlPartialEqual(expected_shadow_session, suite, "./entry/command[@id='m0-f1']/../session") def test_shadow_form_action_modifications(self): # Confirm that shadow form action modifications are reflected in the suite file original_actions = self.shadow_form.extra_actions.load_update_cases try: self.shadow_form.extra_actions.load_update_cases = [ LoadUpdateAction( case_tag="load_0", case_type="doctor", details_module=self.basic_module.unique_id ) ] suite = self.factory.app.create_suite() finally: # reset the actions self.shadow_form.extra_actions.load_update_cases = original_actions # Confirm that the source session has not changed: expected_source_session = """ <partial> <session> <datum detail-confirm="m0_case_long" detail-select="m0_case_short" id="case_id_load_0" nodeset="instance('casedb')/casedb/case[@case_type='patient'][@status='open']" value="./@case_id" /> <datum function="uuid()" id="case_id_new_patient_0"/> </session> </partial> """ self.assertXmlPartialEqual(expected_source_session, suite, "./entry/command[@id='m0-f0']/../session") # Confirm that the shadow session HAS changed: expected_shadow_session = """ <partial> <session> <datum detail-confirm="m1_case_long" detail-select="m1_case_short" id="case_id_load_0" nodeset="instance('casedb')/casedb/case[@case_type='doctor'][@status='open']" value="./@case_id" /> <datum function="uuid()" id="case_id_new_patient_0"/> </session> </partial> """ self.assertXmlPartialEqual(expected_shadow_session, suite, "./entry/command[@id='m0-f1']/../session") def test_shadow_form_action_reordering(self): # Confirm that the ordering of the actions in the shadow form is used, not the source ordering source_form_original_actions = self.form0.actions.load_update_cases shadow_form_original_actions = self.shadow_form.extra_actions.load_update_cases try: # Add an action to the source form self.form0.actions.load_update_cases = [ LoadUpdateAction( case_type="patient", case_tag="load_0", case_properties={ "name": "/data/name" }, preload={ "/data/name": "name" }, details_module=self.advanced_module.unique_id, ), LoadUpdateAction( case_type="patient", case_tag="load_1", case_properties={ "name": "/data/name" }, preload={ "/data/name": "name" }, details_module=self.advanced_module.unique_id, ) ] # specify a different order in the shadow form self.shadow_form.extra_actions.load_update_cases = [ LoadUpdateAction( case_tag="load_1", case_type="patient", details_module=self.advanced_module.unique_id, ), LoadUpdateAction( case_tag="load_0", case_type="patient", details_module=self.advanced_module.unique_id, ) ] suite = self.factory.app.create_suite() finally: # reset the actions self.form0.actions.load_update_cases = source_form_original_actions self.shadow_form.extra_actions.load_update_cases = shadow_form_original_actions # Confirm that the load_0 action comes first in the source form self.assertXmlHasXpath( suite, "./entry/command[@id='m0-f0']/../session/datum[@id='case_id_load_0' and position() = 1]" ) self.assertXmlHasXpath( suite, "./entry/command[@id='m0-f0']/../session/datum[@id='case_id_load_1' and position() = 2]" ) # Confirm that the load_0 action comes second in the shadow form self.assertXmlHasXpath( suite, "./entry/command[@id='m0-f1']/../session/datum[@id='case_id_load_1' and position() = 1]" ) self.assertXmlHasXpath( suite, "./entry/command[@id='m0-f1']/../session/datum[@id='case_id_load_0' and position() = 2]" )