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 &gt; 33"/>
          </menu>
        </partial>
        """
        self.assertXmlPartialEqual(XML, factory.app.create_suite(), "./menu[@id='m1']")
Example #3
0
    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)
Example #4
0
    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 &gt; 33"/>
          </menu>
        </partial>
        """
        self.assertXmlPartialEqual(XML, factory.app.create_suite(), "./menu[@id='m1']")
 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 _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
Example #7
0
    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, '', '')
Example #8
0
    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")
Example #9
0
    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
Example #11
0
    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())
Example #12
0
    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)
Example #13
0
    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")
Example #14
0
    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")
Example #15
0
 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',
        ])
Example #17
0
    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")
Example #18
0
    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")
Example #20
0
    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")
Example #23
0
    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_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")
Example #26
0
    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_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',
        )
Example #28
0
    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")
Example #30
0
    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)
Example #31
0
    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_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_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")
Example #34
0
    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())
Example #35
0
    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())
Example #36
0
    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())
Example #37
0
    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())
Example #38
0
    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")
Example #39
0
    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
        )
Example #40
0
    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)
Example #42
0
    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())
Example #43
0
    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
Example #44
0
    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]")
Example #45
0
    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")
Example #46
0
    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")
Example #47
0
    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]"
        )
Example #48
0
    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]")
Example #50
0
    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)
Example #52
0
    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
        )
Example #54
0
    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()
Example #57
0
    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
Example #58
0
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]"
        )
Example #59
0
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]"
        )