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 _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_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_return_to_shadow_module(self, *args): factory = AppFactory(build_version='2.9.0') m0, m0f0 = factory.new_basic_module('enroll child', 'child') factory.form_requires_case(m0f0) m0f0.post_form_workflow = WORKFLOW_MODULE m1 = factory.new_shadow_module('shadow_module', m0, with_form=False) expected = """ <partial> <stack> <create> <command value="'m1'"/> </create> </stack> </partial> """ self.assertXmlPartialEqual(expected, factory.app.create_suite(), "./entry[2]/stack")
class HandleShadowChildModulesTest(TestCase): """Test how shadow child modules are created and deleted """ def setUp(self): super().setUp() self.domain = "test-domain" self.factory = AppFactory(domain=self.domain) # m0 self.basic_module, self.form0 = self.factory.new_basic_module( "basic_module", "parrot") form1 = self.factory.new_form(self.basic_module) # m1 self.child_module, form2 = self.factory.new_basic_module( "child_module", "parrot", parent_module=self.basic_module) self.child_module.put_in_root = True self.form3 = self.factory.new_form(self.child_module) # m2 self.shadow_module = self.factory.new_shadow_module("shadow_module", self.basic_module, with_form=False) self.shadow_module.excluded_form_ids = [ self.form0.unique_id, self.form3.unique_id ] self.factory.app.save() self.app = self.factory.app def tearDown(self): delete_all_apps() super().tearDown() def test_creates_new_modules(self): handle_shadow_child_modules( self.app, self.app.get_module_by_unique_id(self.shadow_module.unique_id)) app = Application.get(self.app.get_id) # A new shadow module should be created whose module source is the child self.assertEqual(len(app.modules), 4) self.assertEqual(app.modules[3].module_type, "shadow") self.assertEqual(app.modules[3].source_module_id, self.child_module.unique_id) # excluded form ids should move from the parent to the child module, # retaining the pertinent parent ids self.assertItemsEqual(app.modules[3].excluded_form_ids, [self.form3.unique_id]) self.assertItemsEqual( app.get_module_by_unique_id( self.shadow_module.unique_id).excluded_form_ids, [self.form0.unique_id], ) # Calling the command again should not make new modules shadow_child_module_id = app.modules[3].unique_id handle_shadow_child_modules( app, app.get_module_by_unique_id(self.shadow_module.unique_id)) app = Application.get(app.get_id) self.assertEqual(len(app.modules), 4) self.assertEqual(app.modules[3].unique_id, shadow_child_module_id) def test_deletes_module_child_removed(self): # Create new module handle_shadow_child_modules( self.app, self.app.get_module_by_unique_id(self.shadow_module.unique_id)) # Change child module's parent app = Application.get(self.app.get_id) app.modules[1].root_module_id = None app.save() # The new shadow module should be deleted, since it is no longer needed handle_shadow_child_modules( app, app.get_module_by_unique_id(self.shadow_module.unique_id)) self.assertEqual(len(app.modules), 3) def test_deletes_module_source_changed(self): # Create new module handle_shadow_child_modules( self.app, self.app.get_module_by_unique_id(self.shadow_module.unique_id)) # Change parent shadow module's source app = Application.get(self.app.get_id) new_module = Module.new_module("name", "en") app.add_module(new_module) app.get_module_by_unique_id(self.shadow_module.unique_id ).source_module_id = new_module.unique_id app.save() self.assertEqual(len(app.modules), 5) # Child shadow module should be removed handle_shadow_child_modules( app, app.get_module_by_unique_id(self.shadow_module.unique_id)) self.assertEqual(len(app.modules), 4) def test_shadow_source_is_child(self): # If the source is a child, the parent of the shadow should be the same as the source shadow_child = self.factory.new_shadow_module("shadow_child_module", self.child_module, with_form=False) self.factory.app.save() handle_shadow_child_modules( self.app, self.app.get_module_by_unique_id(shadow_child.unique_id)) app = Application.get(self.app.get_id) shadow_child = app.get_module_by_unique_id(shadow_child.unique_id) self.assertEqual(shadow_child.root_module_id, self.child_module.root_module_id) # change the source shadow_child.source_module_id = self.basic_module.unique_id app.save() handle_shadow_child_modules( app, app.get_module_by_unique_id(shadow_child.unique_id)) app = Application.get(self.app.get_id) shadow_child = app.get_module_by_unique_id(shadow_child.unique_id) self.assertIsNone(shadow_child.root_module_id) def test_all_shadow_module_properties_set(self): ignored_properties = [ "module_type", "source_module_id", "doc_type", "_root_module_id", "forms", "excluded_form_ids", "shadow_module_version", ] required_properties = { prop for prop in vars(ShadowModule) if isinstance( vars(ShadowModule)[prop], jsonobject.base_properties. JsonProperty) and prop not in ignored_properties } copied_properties = { prop for prop, _ in SHADOW_MODULE_PROPERTIES_TO_COPY } self.assertItemsEqual( required_properties - copied_properties, [], (f"Please handle the new property you just added '{required_properties - copied_properties}' " "to ShadowModule in app_manager.views.utils.handle_child_shadow_modules, or add it " "to the ignored_propertieslist in this test."), ) def test_all_base_module_properties_set(self): ignored_properties = [ "doc_type", "root_module_id", "name", "case_type", "unique_id" ] required_properties = { prop for prop in vars(ModuleBase) if isinstance( vars(ModuleBase)[prop], jsonobject.base_properties.JsonProperty ) and prop not in ignored_properties } required_properties |= { prop for prop in vars(NavMenuItemMediaMixin) if isinstance( vars(NavMenuItemMediaMixin)[prop], jsonobject.base_properties. JsonProperty) and prop not in ignored_properties } copied_properties = { prop for prop, _ in MODULE_BASE_PROPERTIES_TO_COPY } self.assertItemsEqual( required_properties - copied_properties, [], (f"Please handle the new property you just added '{required_properties - copied_properties}' " "to ShadowModule in app_manager.views.utils.handle_child_shadow_modules, or add it " "to the ignored_propertieslist in this test."), )
class ShadowModuleFormSelectionSuiteTest(SimpleTestCase, TestXmlMixin): def setUp(self): self.factory = AppFactory() self.basic_module, self.form0 = self.factory.new_basic_module( 'basic_module', 'parrot') self.form0.xmlns = 'http://openrosa.org/formdesigner/firstform' self.form1 = self.factory.new_form(self.basic_module) self.form1.xmlns = 'http://openrosa.org/formdesigner/secondform' self.shadow_module = self.factory.new_shadow_module('shadow_module', self.basic_module, with_form=False) self.child_module, self.form2 = self.factory.new_basic_module( 'child_module', 'parrot', parent_module=self.basic_module) def test_all_forms_selected(self): expected = """ <partial> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> </partial> """ self.assertXmlPartialEqual(expected, self.factory.app.create_suite(), "./menu[@id='m1']") def test_some_forms_selected(self): self.shadow_module.excluded_form_ids = [self.form0.unique_id] expected = """ <partial> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f1"/> </menu> </partial> """ self.assertXmlPartialEqual(expected, self.factory.app.create_suite(), "./menu[@id='m1']") def test_no_forms_selected(self): self.shadow_module.excluded_form_ids = [ self.form0.unique_id, self.form1.unique_id ] self.assertXmlDoesNotHaveXpath(self.factory.app.create_suite(), "./menu[@id='m1']") def test_no_child_forms_selected(self): self.shadow_module.excluded_form_ids = [self.form2.unique_id] self.assertXmlPartialEqual( ''' <partial> <menu id="m0"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="m2" root="m0"> <text> <locale id="modules.m2"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu") self.basic_module.put_in_root = True self.shadow_module.put_in_root = False self.child_module.put_in_root = False self.assertXmlPartialEqual( ''' <partial> <menu id="root"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="m2" root="root"> <text> <locale id="modules.m2"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu") self.basic_module.put_in_root = False self.shadow_module.put_in_root = True self.child_module.put_in_root = False self.assertXmlPartialEqual( ''' <partial> <menu id="m0"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="root"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="m2" root="m0"> <text> <locale id="modules.m2"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu") self.basic_module.put_in_root = False self.shadow_module.put_in_root = False self.child_module.put_in_root = True self.assertXmlPartialEqual( ''' <partial> <menu id="m0"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="m0"> <text> <locale id="modules.m0"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu") self.basic_module.put_in_root = False self.shadow_module.put_in_root = True self.child_module.put_in_root = True self.assertXmlPartialEqual( ''' <partial> <menu id="m0"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="root"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="m0"> <text> <locale id="modules.m0"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu") self.basic_module.put_in_root = True self.shadow_module.put_in_root = False self.child_module.put_in_root = True self.assertXmlPartialEqual( ''' <partial> <menu id="root"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="root"> <text> <locale id="modules.m2"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu") self.basic_module.put_in_root = True self.shadow_module.put_in_root = True self.child_module.put_in_root = False self.assertXmlPartialEqual( ''' <partial> <menu id="root"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="root"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="m2" root="root"> <text> <locale id="modules.m2"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu") self.basic_module.put_in_root = True self.shadow_module.put_in_root = True self.child_module.put_in_root = True self.assertXmlPartialEqual( ''' <partial> <menu id="root"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="root"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="root"> <text> <locale id="modules.m2"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu") def test_form_added(self): self.shadow_module.excluded_form_ids = [self.form0.unique_id] self.factory.new_form(self.basic_module) expected = """ <partial> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f1"/> <command id="m1-f2"/> </menu> </partial> """ self.assertXmlPartialEqual(expected, self.factory.app.create_suite(), "./menu[@id='m1']") def test_form_removed(self): self.basic_module.forms.remove(self.form1) expected = """ <partial> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> </menu> </partial> """ self.assertXmlPartialEqual(expected, self.factory.app.create_suite(), "./menu[@id='m1']") def test_forms_reordered(self): expected_before = """ <partial> <form>http://openrosa.org/formdesigner/firstform</form> <form>http://openrosa.org/formdesigner/secondform</form> <form>http://openrosa.org/formdesigner/firstform</form> <form>http://openrosa.org/formdesigner/secondform</form> </partial> """ self.assertXmlPartialEqual(expected_before, self.factory.app.create_suite(), "./entry/form") # Swap forms around self.basic_module.forms = [self.form1, self.form0] expected_after = """ <partial> <form>http://openrosa.org/formdesigner/secondform</form> <form>http://openrosa.org/formdesigner/firstform</form> <form>http://openrosa.org/formdesigner/secondform</form> <form>http://openrosa.org/formdesigner/firstform</form> </partial> """ self.assertXmlPartialEqual(expected_after, self.factory.app.create_suite(), "./entry/form") def _create_parent_selection_app(self): ''' setUp creates an app with three modules: basic, shadow, and child, all using parrot cases. This app adds an additional module that uses child cases (baby_parrot) and uses it as the source for the shadow module. Tests verify that when the shadow module uses parent child selection, it fetches both parrot and baby_parrot datums, using the correct details. ''' self.factory.form_requires_case(self.form0) self.child_case_module, self.form3 = self.factory.new_basic_module( 'child_case_module', 'baby_parrot') self.factory.form_requires_case(self.form3, parent_case_type='parrot') self.shadow_module.source_module_id = self.child_case_module.unique_id self.shadow_module.parent_select.active = True def test_parent_selection_first(self): self._create_parent_selection_app() self.shadow_module.parent_select.module_id = self.basic_module.unique_id # Test the entry for the shadow module's single form expected_entry = """ <partial> <entry> <command id="m1-f0"> <text> <locale id="forms.m3f0"/> </text> </command> <instance id="casedb" src="jr://instance/casedb"/> <instance id="commcaresession" src="jr://instance/session"/> <session> <datum id="parent_id" nodeset="instance('casedb')/casedb/case[@case_type='parrot'][@status='open']" value="./@case_id" detail-select="m0_case_short"/> <datum id="case_id" nodeset="instance('casedb')/casedb/case[@case_type='baby_parrot'][@status='open'][index/parent=instance('commcaresession')/session/data/parent_id]" value="./@case_id" detail-select="m1_case_short" detail-confirm="m1_case_long"/> </session> </entry> </partial> """ self.assertXmlPartialEqual(expected_entry, self.factory.app.create_suite(), './entry[3]') def test_parent_selection_different_module_than_source(self): self._create_parent_selection_app() self.additional_basic_module, dummy = self.factory.new_basic_module( 'additional_basic_module', 'parrot') self.child_case_module.parent_select.active = True self.child_case_module.parent_select.module_id = self.basic_module.unique_id self.shadow_module.parent_select.module_id = self.additional_basic_module.unique_id # Test the entry for the shadow module's single form expected_entry = """ <partial> <entry> <command id="m1-f0"> <text> <locale id="forms.m3f0"/> </text> </command> <instance id="casedb" src="jr://instance/casedb"/> <instance id="commcaresession" src="jr://instance/session"/> <session> <datum id="parent_id" nodeset="instance('casedb')/casedb/case[@case_type='parrot'][@status='open']" value="./@case_id" detail-select="m4_case_short"/> <datum id="case_id" nodeset="instance('casedb')/casedb/case[@case_type='baby_parrot'][@status='open'][index/parent=instance('commcaresession')/session/data/parent_id]" value="./@case_id" detail-select="m1_case_short" detail-confirm="m1_case_long"/> </session> </entry> </partial> """ self.assertXmlPartialEqual(expected_entry, self.factory.app.create_suite(), './entry[3]')
class ShadowModuleFormSelectionSuiteTest(SimpleTestCase, TestXmlMixin): def setUp(self): self.factory = AppFactory() self.basic_module, self.form0 = self.factory.new_basic_module('basic_module', 'parrot') self.form0.xmlns = 'http://openrosa.org/formdesigner/firstform' self.form1 = self.factory.new_form(self.basic_module) self.form1.xmlns = 'http://openrosa.org/formdesigner/secondform' self.shadow_module = self.factory.new_shadow_module('shadow_module', self.basic_module, with_form=False) self.child_module, self.form2 = self.factory.new_basic_module('child_module', 'parrot', parent_module=self.basic_module) def test_all_forms_selected(self): expected = """ <partial> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> </partial> """ self.assertXmlPartialEqual( expected, self.factory.app.create_suite(), "./menu[@id='m1']" ) def test_some_forms_selected(self): self.shadow_module.excluded_form_ids = [self.form0.unique_id] expected = """ <partial> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f1"/> </menu> </partial> """ self.assertXmlPartialEqual( expected, self.factory.app.create_suite(), "./menu[@id='m1']" ) def test_no_forms_selected(self): self.shadow_module.excluded_form_ids = [self.form0.unique_id, self.form1.unique_id] self.assertXmlDoesNotHaveXpath(self.factory.app.create_suite(), "./menu[@id='m1']") def test_no_child_forms_selected(self): self.shadow_module.excluded_form_ids = [self.form2.unique_id] self.assertXmlPartialEqual( ''' <partial> <menu id="m0"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="m2" root="m0"> <text> <locale id="modules.m2"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu" ) self.basic_module.put_in_root = True self.shadow_module.put_in_root = False self.child_module.put_in_root = False self.assertXmlPartialEqual( ''' <partial> <menu id="root"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="m2" root="root"> <text> <locale id="modules.m2"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu" ) self.basic_module.put_in_root = False self.shadow_module.put_in_root = True self.child_module.put_in_root = False self.assertXmlPartialEqual( ''' <partial> <menu id="m0"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="root"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="m2" root="m0"> <text> <locale id="modules.m2"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu" ) self.basic_module.put_in_root = False self.shadow_module.put_in_root = False self.child_module.put_in_root = True self.assertXmlPartialEqual( ''' <partial> <menu id="m0"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="m0"> <text> <locale id="modules.m0"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu" ) self.basic_module.put_in_root = False self.shadow_module.put_in_root = True self.child_module.put_in_root = True self.assertXmlPartialEqual( ''' <partial> <menu id="m0"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="root"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="m0"> <text> <locale id="modules.m0"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu" ) self.basic_module.put_in_root = True self.shadow_module.put_in_root = False self.child_module.put_in_root = True self.assertXmlPartialEqual( ''' <partial> <menu id="root"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="root"> <text> <locale id="modules.m2"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu" ) self.basic_module.put_in_root = True self.shadow_module.put_in_root = True self.child_module.put_in_root = False self.assertXmlPartialEqual( ''' <partial> <menu id="root"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="root"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="m2" root="root"> <text> <locale id="modules.m2"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu" ) self.basic_module.put_in_root = True self.shadow_module.put_in_root = True self.child_module.put_in_root = True self.assertXmlPartialEqual( ''' <partial> <menu id="root"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="root"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="root"> <text> <locale id="modules.m2"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu" ) def test_form_added(self): self.shadow_module.excluded_form_ids = [self.form0.unique_id] self.factory.new_form(self.basic_module) expected = """ <partial> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f1"/> <command id="m1-f2"/> </menu> </partial> """ self.assertXmlPartialEqual( expected, self.factory.app.create_suite(), "./menu[@id='m1']" ) def test_form_removed(self): self.basic_module.forms.remove(self.form1) expected = """ <partial> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> </menu> </partial> """ self.assertXmlPartialEqual( expected, self.factory.app.create_suite(), "./menu[@id='m1']" ) def test_forms_reordered(self): expected_before = """ <partial> <form>http://openrosa.org/formdesigner/firstform</form> <form>http://openrosa.org/formdesigner/secondform</form> <form>http://openrosa.org/formdesigner/firstform</form> <form>http://openrosa.org/formdesigner/secondform</form> </partial> """ self.assertXmlPartialEqual( expected_before, self.factory.app.create_suite(), "./entry/form" ) # Swap forms around self.basic_module.forms = [self.form1, self.form0] expected_after = """ <partial> <form>http://openrosa.org/formdesigner/secondform</form> <form>http://openrosa.org/formdesigner/firstform</form> <form>http://openrosa.org/formdesigner/secondform</form> <form>http://openrosa.org/formdesigner/firstform</form> </partial> """ self.assertXmlPartialEqual( expected_after, self.factory.app.create_suite(), "./entry/form" ) def _create_parent_selection_app(self): ''' setUp creates an app with three modules: basic, shadow, and child, all using parrot cases. This app adds an additional module that uses child cases (baby_parrot) and uses it as the source for the shadow module. Tests verify that when the shadow module uses parent child selection, it fetches both parrot and baby_parrot datums, using the correct details. ''' self.factory.form_requires_case(self.form0) self.child_case_module, self.form3 = self.factory.new_basic_module('child_case_module', 'baby_parrot') self.factory.form_requires_case(self.form3, parent_case_type='parrot') self.shadow_module.source_module_id = self.child_case_module.unique_id self.shadow_module.parent_select.active = True def test_parent_selection_first(self): self._create_parent_selection_app() self.shadow_module.parent_select.module_id = self.basic_module.unique_id # Test the entry for the shadow module's single form expected_entry = """ <partial> <entry> <command id="m1-f0"> <text> <locale id="forms.m3f0"/> </text> </command> <instance id="casedb" src="jr://instance/casedb"/> <instance id="commcaresession" src="jr://instance/session"/> <session> <datum id="parent_id" nodeset="instance('casedb')/casedb/case[@case_type='parrot'][@status='open']" value="./@case_id" detail-select="m0_case_short"/> <datum id="case_id" nodeset="instance('casedb')/casedb/case[@case_type='baby_parrot'][@status='open'][index/parent=instance('commcaresession')/session/data/parent_id]" value="./@case_id" detail-select="m1_case_short" detail-confirm="m1_case_long"/> </session> </entry> </partial> """ self.assertXmlPartialEqual( expected_entry, self.factory.app.create_suite(), './entry[3]' ) def test_parent_selection_different_module_than_source(self): self._create_parent_selection_app() self.additional_basic_module, dummy = self.factory.new_basic_module('additional_basic_module', 'parrot') self.child_case_module.parent_select.active = True self.child_case_module.parent_select.module_id = self.basic_module.unique_id self.shadow_module.parent_select.module_id = self.additional_basic_module.unique_id # Test the entry for the shadow module's single form expected_entry = """ <partial> <entry> <command id="m1-f0"> <text> <locale id="forms.m3f0"/> </text> </command> <instance id="casedb" src="jr://instance/casedb"/> <instance id="commcaresession" src="jr://instance/session"/> <session> <datum id="parent_id" nodeset="instance('casedb')/casedb/case[@case_type='parrot'][@status='open']" value="./@case_id" detail-select="m4_case_short"/> <datum id="case_id" nodeset="instance('casedb')/casedb/case[@case_type='baby_parrot'][@status='open'][index/parent=instance('commcaresession')/session/data/parent_id]" value="./@case_id" detail-select="m1_case_short" detail-confirm="m1_case_long"/> </session> </entry> </partial> """ self.assertXmlPartialEqual( expected_entry, self.factory.app.create_suite(), './entry[3]' )
class ShadowModuleFormSelectionSuiteTest(SimpleTestCase, TestXmlMixin): def setUp(self): self.factory = AppFactory() self.basic_module, self.form0 = self.factory.new_basic_module('basic_module', 'parrot') self.form0.xmlns = 'http://openrosa.org/formdesigner/firstform' self.form1 = self.factory.new_form(self.basic_module) self.form1.xmlns = 'http://openrosa.org/formdesigner/secondform' self.shadow_module = self.factory.new_shadow_module('shadow_module', self.basic_module, with_form=False) self.child_module, self.form2 = self.factory.new_basic_module('child_module', 'parrot', parent_module=self.basic_module) def test_all_forms_selected(self): expected = """ <partial> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> </partial> """ self.assertXmlPartialEqual( expected, self.factory.app.create_suite(), "./menu[@id='m1']" ) def test_some_forms_selected(self): self.shadow_module.excluded_form_ids = [self.form0.unique_id] expected = """ <partial> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f1"/> </menu> </partial> """ self.assertXmlPartialEqual( expected, self.factory.app.create_suite(), "./menu[@id='m1']" ) def test_no_forms_selected(self): self.shadow_module.excluded_form_ids = [self.form0.unique_id, self.form1.unique_id] self.assertXmlDoesNotHaveXpath(self.factory.app.create_suite(), "./menu[@id='m1']") def test_no_child_forms_selected(self): self.shadow_module.excluded_form_ids = [self.form2.unique_id] self.assertXmlPartialEqual( ''' <partial> <menu id="m0"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="m2" root="m0"> <text> <locale id="modules.m2"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu" ) self.basic_module.put_in_root = True self.shadow_module.put_in_root = False self.child_module.put_in_root = False self.assertXmlPartialEqual( ''' <partial> <menu id="root"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="m2" root="root"> <text> <locale id="modules.m2"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu" ) self.basic_module.put_in_root = False self.shadow_module.put_in_root = True self.child_module.put_in_root = False self.assertXmlPartialEqual( ''' <partial> <menu id="m0"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="root"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="m2" root="m0"> <text> <locale id="modules.m2"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu" ) self.basic_module.put_in_root = False self.shadow_module.put_in_root = False self.child_module.put_in_root = True self.assertXmlPartialEqual( ''' <partial> <menu id="m0"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="m0"> <text> <locale id="modules.m2"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu" ) self.basic_module.put_in_root = False self.shadow_module.put_in_root = True self.child_module.put_in_root = True self.assertXmlPartialEqual( ''' <partial> <menu id="m0"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="root"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="m0"> <text> <locale id="modules.m2"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu" ) self.basic_module.put_in_root = True self.shadow_module.put_in_root = False self.child_module.put_in_root = True self.assertXmlPartialEqual( ''' <partial> <menu id="root"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="root"> <text> <locale id="modules.m2"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu" ) self.basic_module.put_in_root = True self.shadow_module.put_in_root = True self.child_module.put_in_root = False self.assertXmlPartialEqual( ''' <partial> <menu id="root"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="root"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="m2" root="root"> <text> <locale id="modules.m2"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu" ) self.basic_module.put_in_root = True self.shadow_module.put_in_root = True self.child_module.put_in_root = True self.assertXmlPartialEqual( ''' <partial> <menu id="root"> <text> <locale id="modules.m0"/> </text> <command id="m0-f0"/> <command id="m0-f1"/> </menu> <menu id="root"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> <command id="m1-f1"/> </menu> <menu id="root"> <text> <locale id="modules.m2"/> </text> <command id="m2-f0"/> </menu> </partial> ''', self.factory.app.create_suite(), "./menu" ) def test_form_added(self): self.shadow_module.excluded_form_ids = [self.form0.unique_id] self.factory.new_form(self.basic_module) expected = """ <partial> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f1"/> <command id="m1-f2"/> </menu> </partial> """ self.assertXmlPartialEqual( expected, self.factory.app.create_suite(), "./menu[@id='m1']" ) def test_form_removed(self): self.basic_module.forms.remove(self.form1) expected = """ <partial> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0"/> </menu> </partial> """ self.assertXmlPartialEqual( expected, self.factory.app.create_suite(), "./menu[@id='m1']" ) def test_forms_reordered(self): expected_before = """ <partial> <form>http://openrosa.org/formdesigner/firstform</form> <form>http://openrosa.org/formdesigner/secondform</form> <form>http://openrosa.org/formdesigner/firstform</form> <form>http://openrosa.org/formdesigner/secondform</form> </partial> """ self.assertXmlPartialEqual( expected_before, self.factory.app.create_suite(), "./entry/form" ) # Swap forms around self.basic_module.forms = [self.form1, self.form0] expected_after = """ <partial> <form>http://openrosa.org/formdesigner/secondform</form> <form>http://openrosa.org/formdesigner/firstform</form> <form>http://openrosa.org/formdesigner/secondform</form> <form>http://openrosa.org/formdesigner/firstform</form> </partial> """ self.assertXmlPartialEqual( expected_after, self.factory.app.create_suite(), "./entry/form" )
class MultiSelectCaseListTests(SimpleTestCase, TestXmlMixin): file_path = ('data', 'suite', 'multi_select_case_list') def setUp(self): self.factory = AppFactory(domain="multiple-referrals") self.app_id = uuid4().hex self.factory.app._id = self.app_id self.module, self.form = self.factory.new_basic_module( 'basic', 'person') self.factory.form_requires_case(self.form, 'person') self.form.xmlns = "some-xmlns" self.module.case_details.short.multi_select = True self.module.search_config = CaseSearch( search_label=CaseSearchLabel(label={'en': 'Search'}), properties=[ CaseSearchProperty(name=field) for field in ['name', 'greatest_fear'] ], ) self.module.assign_references() def test_multi_select_case_list(self): suite = self.factory.app.create_suite() self.assertXmlPartialEqual( """ <partial> <entry> <form>some-xmlns</form> <command id="m0-f0"> <text> <locale id="forms.m0f0"/> </text> </command> <instance id="casedb" src="jr://instance/casedb"/> <session> <instance-datum id="selected_cases" nodeset="instance('casedb')/casedb/case[@case_type='person'][@status='open']" value="./@case_id" detail-select="m0_case_short" detail-confirm="m0_case_long"/> </session> </entry> </partial> """, suite, "./entry", ) self.assertXmlPartialEqual( self.get_xml('basic_remote_request').decode('utf-8').format( app_id=self.factory.app._id), suite, "./remote-request", ) def test_session_schema(self): # Session schema should not contain case self.assertEqual( get_session_schema(self.form), { 'id': 'commcaresession', 'name': 'Session', 'path': '/session', 'structure': {}, 'uri': 'jr://instance/session' }) @flag_enabled('APP_BUILDER_SHADOW_MODULES') def test_shadow_modules(self): shadow_module = self.factory.new_shadow_module('shadow', self.module, with_form=False) self.assertTrue(shadow_module.is_multi_select()) del self.factory.app.modules[shadow_module.id] @flag_enabled('USH_CASE_CLAIM_UPDATES') def test_multi_select_case_list_auto_launch(self): self.module.search_config.auto_launch = True suite = self.factory.app.create_suite() self.assertXmlPartialEqual( """ <partial> <action auto_launch="true()" redo_last="false"> <display> <text> <locale id="case_search.m0"/> </text> </display> <stack> <push> <mark/> <command value="'search_command.m0'"/> </push> </stack> </action> </partial> """, suite, "./detail[@id='m0_case_short']/action", ) self.assertXmlPartialEqual( """ <partial> <action auto_launch="false()" redo_last="true"> <display> <text> <locale id="case_search.m0.again"/> </text> </display> <stack> <push> <mark/> <command value="'search_command.m0'"/> </push> </stack> </action> </partial> """, suite, "./detail[@id='m0_search_short']/action", )