Skip to content

Commit

Permalink
add: test cases for select search() appearance behaviour (XLSForm#693)
Browse files Browse the repository at this point in the history
  • Loading branch information
lindsay-stevens authored Jan 29, 2024
1 parent 8b98e33 commit 0f6b4a5
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 79 deletions.
Binary file removed tests/example_xls/search_and_select.xlsx
Binary file not shown.
40 changes: 0 additions & 40 deletions tests/test_expected_output/search_and_select.xml

This file was deleted.

220 changes: 184 additions & 36 deletions tests/test_translations.py
Original file line number Diff line number Diff line change
Expand Up @@ -1554,70 +1554,218 @@ def test_choice_name_containing_dash_output_itext(self):


class TestTranslationsSearchAppearance(PyxformTestCase):
"""Translations behaviour with the search() appearance."""
"""
Translations behaviour with the search() appearance.
The search() appearance is a Collect-only feature, so ODK Validate is run for these
tests to try and ensure that the output will be accepted by Collect. In particular,
the search() appearance requires in-line (body) items for choices.
"""

@classmethod
def setUpClass(cls) -> None:
cls.run_odk_validate = True

@staticmethod
def xpath_body_select_search_appearance(
qname: str, appearance: str = "search('my_file')"
) -> str:
return f"""
/h:html/h:body/x:select1[
@ref='/test_name/{qname}'
and @appearance="{appearance}"
]
"""

@staticmethod
def xpath_body_select_config_choice(qname: str, cname: str, cvname: str) -> str:
return f"""
/h:html/h:body/x:select1[@ref='/test_name/{qname}']/x:item[
./x:value/text()='{cvname}'
and ./x:label[@ref="jr:itext('{cname}-0')"]
]
"""

def test_shared_choice_list(self):
"""Should include translation for search() items, sharing the choice list"""
"""Should include translation for search() items, when sharing the choice list"""
md = """
| survey | | | | | |
| | type | name | label::en | label::fr | appearance |
| | select_one c1 | q1 | Question 1 | Chose 1 | search('my_file') |
| | select_one c2 | q2 | Question 2 | Chose 2 | |
| choices | | | | |
| | list_name | name | label::en | label::fr |
| | c1 | na | la-e | la-f |
| | c1 | nb | lb-e | lb-f |
| | c2 | na | la-e | la-f |
| survey | | | | | |
| | type | name | label::en | label::fr | appearance |
| | select_one c1 | q1 | Question 1 | Chose 1 | search('my_file') |
| | select_one c1 | q2 | Question 2 | Chose 2 | search('my_file', 'matches', 'filtercol', 'x1') |
| choices | | | | |
| | list_name | name | label::en | label::fr |
| | c1 | id | label_en | label_fr |
"""
self.assertPyxformXform(
md=md,
run_odk_validate=True,
run_odk_validate=self.run_odk_validate,
xml__xpath_match=[
"/h:html/h:body/x:select1/x:item[./x:value/text()='na']",
xpc.model_itext_choice_text_label_by_pos("en", "c1", ("la-e", "lb-e")),
xpc.model_itext_choice_text_label_by_pos("fr", "c1", ("la-f", "lb-f")),
xpc.model_itext_choice_text_label_by_pos("en", "c2", ("la-e",)),
xpc.model_itext_choice_text_label_by_pos("fr", "c2", ("la-f",)),
self.xpath_body_select_search_appearance("q1"),
self.xpath_body_select_config_choice("q1", "c1", "id"),
self.xpath_body_select_search_appearance(
"q2", "search('my_file', 'matches', 'filtercol', 'x1')"
),
self.xpath_body_select_config_choice("q2", "c1", "id"),
xpc.model_instance_choices_itext("c1", ("id",)),
xpc.model_itext_choice_text_label_by_pos("en", "c1", ("label_en",)),
xpc.model_itext_choice_text_label_by_pos("fr", "c1", ("label_fr",)),
],
)

def test_single_question_single_choice(self):
"""Should include translation for search() items, edge case of single elements"""
def test_usage_with_other_selects(self):
"""Should include translation for search() items, when used with other selects"""
md = """
| survey | | | | | |
| | type | name | label::en | label::fr | appearance |
| | select_one c1 | q1 | Question 1 | Chose 1 | search('my_file') |
| survey | | | | | |
| | type | name | label::en | label::fr | appearance |
| | select_one c1 | q1 | Question 1 | Chose 1 | search('my_file') |
| | select_one c2 | q2 | Question 2 | Chose 2 | |
| choices | | | | |
| | list_name | name | label::en | label::fr |
| | c1 | na | la-e | la-f |
| | list_name | name | label::en | label::fr |
| | c1 | id | label_en | label_fr |
| | c2 | na | la-e | la-f |
| | c2 | nb | lb-e | lb-f |
"""
self.assertPyxformXform(
md=md,
run_odk_validate=self.run_odk_validate,
xml__xpath_match=[
self.xpath_body_select_search_appearance("q1"),
self.xpath_body_select_config_choice("q1", "c1", "id"),
xpc.model_instance_choices_itext("c1", ("id",)),
xpc.model_itext_choice_text_label_by_pos("en", "c1", ("label_en",)),
xpc.model_itext_choice_text_label_by_pos("fr", "c1", ("label_fr",)),
xpc.model_instance_choices_itext("c2", ("na", "nb")),
xpc.model_itext_choice_text_label_by_pos("en", "c2", ("la-e", "lb-e")),
xpc.model_itext_choice_text_label_by_pos("fr", "c2", ("la-f", "lb-f")),
],
)

def test_usage_with_other_selects__invalid_list_reuse_by_non_search_question(self):
"""By design, q2 won't pull data but the test is to document output behaviour."""
md = """
| survey | | | | | |
| | type | name | label::en | label::fr | appearance |
| | select_one c1 | q1 | Question 1 | Chose 1 | search('my_file') |
| | select_one c1 | q2 | Question 2 | Chose 2 | |
| choices | | | | |
| | list_name | name | label::en | label::fr |
| | c1 | id | label_en | label_fr |
"""
self.assertPyxformXform(
md=md,
run_odk_validate=self.run_odk_validate,
xml__xpath_match=[
self.xpath_body_select_search_appearance("q1"),
self.xpath_body_select_config_choice("q1", "c1", "id"),
xpq.body_select1_itemset("q2"),
xpc.model_instance_choices_itext("c1", ("id",)),
xpc.model_itext_choice_text_label_by_pos("en", "c1", ("label_en",)),
xpc.model_itext_choice_text_label_by_pos("fr", "c1", ("label_fr",)),
],
)

def test_single_question_usage(self):
"""Should include translation for search() items, edge case of single question"""
md = """
| survey | | | | | |
| | type | name | label::en | label::fr | appearance |
| | select_one c1 | q1 | Question 1 | Chose 1 | search('my_file') |
| choices | | | | |
| | list_name | name | label::en | label::fr |
| | c1 | id | label_en | label_fr |
"""
self.assertPyxformXform(
md=md,
run_odk_validate=self.run_odk_validate,
xml__xpath_match=[
self.xpath_body_select_search_appearance("q1"),
self.xpath_body_select_config_choice("q1", "c1", "id"),
xpc.model_instance_choices_itext("c1", ("id",)),
xpc.model_itext_choice_text_label_by_pos("en", "c1", ("label_en",)),
xpc.model_itext_choice_text_label_by_pos("fr", "c1", ("label_fr",)),
],
)

def test_additional_static_choices(self):
"""Should include translation for search() items, when adding static choices"""
md = """
| survey | | | | | |
| | type | name | label::en | label::fr | appearance |
| | select_one c1 | q1 | Question 1 | Chose 1 | search('my_file') |
| choices | | | | |
| | list_name | name | label::en | label::fr |
| | c1 | id | label_en | label_fr |
| | c1 | 0 | l0-e | l0-f |
| | c1 | 1 | l1-e | l1-f |
"""
self.assertPyxformXform(
md=md,
run_odk_validate=True,
run_odk_validate=self.run_odk_validate,
xml__xpath_match=[
"/h:html/h:body/x:select1/x:item[./x:value/text()='na']",
xpc.model_itext_choice_text_label_by_pos("en", "c1", ("la-e",)),
xpc.model_itext_choice_text_label_by_pos("fr", "c1", ("la-f",)),
self.xpath_body_select_search_appearance("q1"),
self.xpath_body_select_config_choice("q1", "c1", "id"),
xpc.model_instance_choices_itext("c1", ("id", "0", "1")),
xpc.model_itext_choice_text_label_by_pos(
"en", "c1", ("label_en", "l0-e", "l1-e")
),
xpc.model_itext_choice_text_label_by_pos(
"fr", "c1", ("label_fr", "l0-f", "l1-f")
),
],
)

def test_name_clashes(self):
"""Should include translation for search() items, avoids any name clashes."""
md = """
| survey | | | | | |
| | type | name | label::en | label::fr | appearance |
| | select_one c1-0 | c1-0 | Question 1 | Chose 1 | search('my_file') |
| survey | | | | | |
| | type | name | label::en | label::fr | appearance |
| | select_one c1-0 | c1-0 | Question 1 | Chose 1 | search('my_file') |
| choices | | | | |
| | list_name | name | label::en | label::fr |
| | c1-0 | na | la-e | la-f |
| | c1-0 | id | label_en | label_fr |
"""
self.assertPyxformXform(
md=md,
run_odk_validate=self.run_odk_validate,
xml__xpath_match=[
self.xpath_body_select_search_appearance("c1-0"),
self.xpath_body_select_config_choice("c1-0", "c1-0", "id"),
xpc.model_instance_choices_itext("c1-0", ("id",)),
xpc.model_itext_choice_text_label_by_pos("en", "c1-0", ("label_en",)),
xpc.model_itext_choice_text_label_by_pos("fr", "c1-0", ("label_fr",)),
],
)

def test_search_and_select_xlsx(self):
"""Test to replace the old XLSX-based test fixture, 'search_and_select.xlsx'"""
md = """
| survey | | | | |
| | type | name | label | appearance |
| | select_one fruits | fruit | Choose a fruit | search('fruits') |
| | note | note_fruit | The fruit ${fruit} pulled from csv | |
| choices | | | |
| | list_name | name | label |
| | fruits | name_key | name |
"""
self.assertPyxformXform(
md=md,
run_odk_validate=True,
run_odk_validate=self.run_odk_validate,
xml__xpath_match=[
"/h:html/h:body/x:select1/x:item[./x:value/text()='na']",
xpc.model_itext_choice_text_label_by_pos("en", "c1-0", ("la-e",)),
xpc.model_itext_choice_text_label_by_pos("fr", "c1-0", ("la-f",)),
"/h:html/h:head/x:model[not(descendant::x:itext)]",
xpc.model_instance_choices_label("fruits", (("name_key", "name"),)),
"""
/h:html/h:body/x:select1[
@ref='/test_name/fruit'
and @appearance="search('fruits')"
]/x:item[
./x:value/text()='name_key'
and ./x:label/text()='name'
]
""",
xpq.model_instance_bind("fruit", "string"),
xpq.model_instance_bind("note_fruit", "string"),
"/h:html/h:body/x:input[@ref='/test_name/note_fruit']",
],
)

Expand Down
3 changes: 0 additions & 3 deletions tests/xform_test_case/xlsform_spec_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@ def test_widgets(self):
def test_pull_data(self):
self.compare_xform(file_name="pull_data.xlsx")

def test_search_and_select(self):
self.compare_xform(file_name="search_and_select.xlsx")

def test_default_survey_sheet(self):
self.compare_xform(file_name="survey_no_name.xlsx", set_default_name=False)

Expand Down

0 comments on commit 0f6b4a5

Please sign in to comment.