def test_full_routing_path_with_repeating_sections(self): schema = load_schema_from_name( "test_repeating_sections_with_hub_and_spoke") list_store = ListStore([{ "items": ["abc123", "123abc"], "name": "people", "primary_person": "abc123", }]) router = Router(schema, self.answer_store, list_store, self.progress_store, self.metadata) routing_path = router.full_routing_path() expected_path = [ RoutingPath( [ "primary-person-list-collector", "list-collector", "next-interstitial", "another-list-collector-block", "visitors-block", ], section_id="section", list_name=None, list_item_id=None, ), RoutingPath( [ "proxy", "date-of-birth", "confirm-dob", "sex", "personal-summary" ], section_id="personal-details-section", list_name="people", list_item_id="abc123", ), RoutingPath( [ "proxy", "date-of-birth", "confirm-dob", "sex", "personal-summary" ], section_id="personal-details-section", list_name="people", list_item_id="123abc", ), ] self.assertEqual(routing_path, expected_path)
def test_return_to_final_summary_questionnaire_is_not_complete(self): self.schema = load_schema_from_name( "test_new_routing_to_questionnaire_end_multiple_sections") self.answer_store = AnswerStore([{ "answer_id": "test-answer", "value": "Yes" }]) self.progress_store = ProgressStore([{ "section_id": "test-section", "list_item_id": None, "status": CompletionStatus.COMPLETED, "block_ids": ["test-forced"], }]) current_location = Location(section_id="test-section", block_id="test-forced") routing_path = RoutingPath(["test-forced"], section_id="test-section") next_location = self.router.get_next_location_url( current_location, routing_path, return_to="final-summary") expected_location = Location( section_id="test-section-2", block_id="test-optional", list_item_id=None, ) self.assertEqual(expected_location.url(), next_location)
def test_routing_path_with_repeating_sections(self): schema = load_schema_from_name( "test_repeating_sections_with_hub_and_spoke") progress_store = ProgressStore([{ "section_id": "section", "status": CompletionStatus.COMPLETED, "block_ids": [ "primary-person-list-collector", "list-collector", "next-interstitial", "another-list-collector-block", ], }]) path_finder = PathFinder(schema, self.answer_store, self.list_store, progress_store, self.metadata) repeating_section_id = "personal-details-section" routing_path = path_finder.routing_path( section_id=repeating_section_id, list_item_id="abc123") expected_path = RoutingPath( ["proxy", "date-of-birth", "confirm-dob", "sex"], section_id="personal-details-section", list_name="people", list_item_id="abc123", ) self.assertEqual(routing_path, expected_path)
def test_list_item_conversion_empty_list(fake_questionnaire_store): """Test that the list store is populated with an empty list for lists which do not have answers yet.""" routing_path = [ RoutingPath( ["list-collector", "next-interstitial", "another-list-collector-block"], section_id="section-1", ) ] answer_objects = [ {"answer_id": "last-name", "value": "2", "list_item_id": "RfAGDc"}, {"answer_id": "anyone-else", "value": "No"}, {"answer_id": "another-anyone-else", "value": "No"}, {"answer_id": "extraneous-answer", "value": "Bad", "list_item_id": "123"}, ] fake_questionnaire_store.answer_store = AnswerStore(answer_objects) fake_questionnaire_store.list_store = ListStore() schema = load_schema_from_name("test_list_collector") output = convert_answers( schema, fake_questionnaire_store, routing_path, SUBMITTED_AT ) # Answers not on the routing path del answer_objects[0] del answer_objects[-1] data_dict = json_loads(json_dumps(output["data"]["answers"])) assert sorted(answer_objects, key=lambda x: x["answer_id"]) == sorted( data_dict, key=lambda x: x["answer_id"] )
def test_currency_answer(fake_questionnaire_store): full_routing_path = [RoutingPath(["currency-block"], section_id="section-1")] answers = AnswerStore([Answer("currency-answer", 100).to_dict()]) fake_questionnaire_store.answer_store = answers questionnaire = make_schema( "0.0.3", "section-1", "currency-group", "currency-block", { "id": "currency-question", "answers": [{"id": "currency-answer", "type": "Currency"}], }, ) answer_object = convert_answers( QuestionnaireSchema(questionnaire), fake_questionnaire_store, full_routing_path, SUBMITTED_AT, ) assert len(answer_object["data"]["answers"]) == 1 assert answer_object["data"]["answers"][0].value == 100
def test_radio_answer(fake_questionnaire_store): full_routing_path = [RoutingPath(["radio-block"], section_id="section-1")] answers = AnswerStore([Answer("radio-answer", "Coffee").to_dict()]) fake_questionnaire_store.answer_store = answers questionnaire = make_schema( "0.0.3", "section-1", "radio-group", "radio-block", { "id": "radio-question", "answers": [ { "type": "Radio", "id": "radio-answer", "options": [ {"label": "Coffee", "value": "Coffee"}, {"label": "Tea", "value": "Tea"}, ], } ], }, ) answer_object = convert_answers( QuestionnaireSchema(questionnaire), fake_questionnaire_store, full_routing_path, SUBMITTED_AT, ) assert len(answer_object["data"]["answers"]) == 1 assert answer_object["data"]["answers"][0].value == "Coffee"
def routing_path( self, section_id: str, list_item_id: Optional[str] = None ) -> RoutingPath: """ Visits all the blocks in a section and returns a path given a list of answers. """ blocks: List[Mapping] = [] routing_path_block_ids = [] current_location = Location(section_id=section_id, list_item_id=list_item_id) section = self.schema.get_section(section_id) list_name = self.schema.get_repeating_list_for_section( current_location.section_id ) for group in section["groups"]: if "skip_conditions" in group: if evaluate_skip_conditions( group["skip_conditions"], self.schema, self.metadata, self.answer_store, self.list_store, current_location=current_location, ): continue blocks.extend(group["blocks"]) if blocks: routing_path_block_ids = self._build_routing_path_block_ids( blocks, current_location ) return RoutingPath(routing_path_block_ids, section_id, list_item_id, list_name)
def test_get_routing_path_when_first_block_in_group_skipped(self): # Given schema = load_schema_from_name("test_skip_condition_group") answer_store = AnswerStore() answer_store.add_or_update( Answer(answer_id="do-you-want-to-skip-answer", value="Yes")) # When path_finder = PathFinder( schema, answer_store, self.list_store, self.progress_store, self.metadata, self.response_metadata, ) # Then expected_route = RoutingPath( section_id="default-section", block_ids=["do-you-want-to-skip"], ) self.assertEqual( expected_route, path_finder.routing_path(section_id="default-section"), )
def test_unit_answer(fake_questionnaire_store): full_routing_path = [RoutingPath(["unit-block"], section_id="section-1")] answers = AnswerStore([Answer("unit-answer", 10).to_dict()]) fake_questionnaire_store.answer_store = answers questionnaire = make_schema( "0.0.3", "section-1", "unit-group", "unit-block", { "id": "unit-question", "answers": [{ "id": "unit-answer", "type": "Unit" }] }, ) answer_object = convert_answers(QuestionnaireSchema(questionnaire), fake_questionnaire_store, full_routing_path) assert len(answer_object["data"]["answers"]) == 1 assert answer_object["data"]["answers"][0].value == 10
def test_primary_links_for_section_summary(people_answer_store): schema = load_schema_from_name("test_list_collector_section_summary") summary_context = SectionSummaryContext( language=DEFAULT_LANGUAGE_CODE, schema=schema, answer_store=people_answer_store, list_store=ListStore( [ { "items": ["PlwgoG", "fg0sPd"], "name": "people", "primary_person": "PlwgoG", } ] ), progress_store=ProgressStore(), metadata={"display_address": "70 Abingdon Road, Goathill"}, response_metadata={}, current_location=Location(section_id="section"), routing_path=RoutingPath( [ "primary-person-list-collector", "list-collector", "visitor-list-collector", ], section_id="section", ), ) context = summary_context() list_items = context["summary"]["custom_summary"][0]["list"]["list_items"] assert "/edit-person/" in list_items[0]["edit_link"] assert "/edit-person/" in list_items[1]["edit_link"]
def test_percentage_answer(fake_questionnaire_store): routing_path = RoutingPath(["percentage-block"], section_id="section-1") fake_questionnaire_store.answer_store = AnswerStore( [Answer("percentage-answer", 100).to_dict()]) question = { "id": "percentage-question", "answers": [{ "id": "percentage-answer", "type": "Percentage", "q_code": "1" }], } questionnaire = make_schema("0.0.1", "section-1", "percentage-block", "percentage-block", question) # When answer_object = convert_answers(QuestionnaireSchema(questionnaire), fake_questionnaire_store, routing_path) # Then assert len(answer_object["data"]) == 1 assert answer_object["data"]["1"] == "100"
def test_converter_checkboxes_with_q_codes_and_empty_other_value( fake_questionnaire_store): routing_path = RoutingPath(["crisps"], section_id="food") fake_questionnaire_store.answer_store = AnswerStore([ Answer("crisps-answer", ["Ready salted", "Other"]).to_dict(), Answer("other-answer-mandatory", "").to_dict(), ]) question = { "id": "crisps-question", "answers": [{ "id": "crisps-answer", "type": "Checkbox", "options": [ { "label": "Ready salted", "value": "Ready salted", "q_code": "1" }, { "label": "Sweet chilli", "value": "Sweet chilli", "q_code": "2" }, { "label": "Cheese and onion", "value": "Cheese and onion", "q_code": "3", }, { "label": "Other", "q_code": "4", "description": "Choose any other flavour", "value": "Other", "detail_answer": { "mandatory": True, "id": "other-answer-mandatory", "label": "Please specify other", "type": "TextField", }, }, ], }], } questionnaire = make_schema("0.0.1", "section-1", "favourite-food", "crisps", question) # When answer_object = convert_answers(QuestionnaireSchema(questionnaire), fake_questionnaire_store, routing_path) # Then assert len(answer_object["data"]) == 2 assert answer_object["data"]["1"] == "Ready salted" assert answer_object["data"]["4"] == "Other"
def test_is_none_on_first_block_single_section(self): self.schema = load_schema_from_name("test_checkbox") self.progress_store = ProgressStore([{ "section_id": "default-section", "list_item_id": None, "status": CompletionStatus.IN_PROGRESS, "block_ids": ["mandatory-checkbox"], }]) routing_path = RoutingPath( [ "mandatory-checkbox", "non-mandatory-checkbox", "single-checkbox" ], section_id="default-section", ) current_location = Location(section_id="default-section", block_id="mandatory-checkbox") previous_location_url = self.router.get_previous_location_url( current_location, routing_path) self.assertIsNone(previous_location_url)
def test_return_to_final_summary_section_is_in_progress(self): self.schema = load_schema_from_name("test_submit_with_summary") self.progress_store = ProgressStore([{ "section_id": "default-section", "list_item_id": None, "status": CompletionStatus.IN_PROGRESS, "block_ids": [ "radio", "dessert", "dessert-confirmation", "numbers", ], }]) current_location = Location(section_id="default-section", block_id="dessert") routing_path = RoutingPath( ["radio", "dessert", "dessert-confirmation", "numbers"], section_id="default-section", ) previous_location = self.router.get_previous_location_url( current_location, routing_path, return_to="final-summary", return_to_answer_id="dessert-answer", ) self.assertIn( "/questionnaire/radio/?return_to=final-summary#dessert-answer", previous_location, )
def test_return_to_section_summary_section_is_in_progress(self): self.schema = load_schema_from_name("test_section_summary") self.progress_store = ProgressStore([{ "section_id": "property-details-section", "list_item_id": None, "status": CompletionStatus.IN_PROGRESS, "block_ids": ["insurance-type", "insurance-address", "listed"], }]) current_location = Location(section_id="property-details-section", block_id="insurance-address") routing_path = RoutingPath( ["insurance-type", "insurance-address", "listed"], section_id="default-section", ) previous_location_url = self.router.get_previous_location_url( current_location, routing_path, return_to="section-summary", return_to_answer_id="insurance-address-answer", ) self.assertIn( "/questionnaire/insurance-type/?return_to=section-summary#insurance-address-answer", previous_location_url, )
def test_routing_path_with_complete_introduction(self): schema = load_schema_from_name("test_introduction") section_id = schema.get_section_id_for_block_id("introduction") progress_store = ProgressStore([{ "section_id": "introduction-section", "list_item_id": None, "status": CompletionStatus.COMPLETED, "block_ids": ["introduction"], }]) expected_routing_path = RoutingPath( ["introduction", "general-business-information-completed"], section_id="introduction-section", ) path_finder = PathFinder( schema, self.answer_store, self.list_store, progress_store, self.metadata, self.response_metadata, ) routing_path = path_finder.routing_path(section_id=section_id) self.assertEqual(routing_path, expected_routing_path)
def test_new_routing_path_should_skip_group(self): # Given schema = load_schema_from_name("test_new_skip_condition_group") section_id = schema.get_section_id_for_block_id("do-you-want-to-skip") answer_store = AnswerStore() answer_store.add_or_update( Answer(answer_id="do-you-want-to-skip-answer", value="Yes")) progress_store = ProgressStore([{ "section_id": "default-section", "list_item_id": None, "status": CompletionStatus.COMPLETED, "block_ids": ["do-you-want-to-skip"], }]) # When path_finder = PathFinder( schema, answer_store, self.list_store, progress_store, self.metadata, self.response_metadata, ) routing_path = path_finder.routing_path(section_id=section_id) # Then expected_routing_path = RoutingPath( ["do-you-want-to-skip"], section_id="default-section", ) self.assertEqual(routing_path, expected_routing_path)
def test_answer_without_qcode(fake_questionnaire_store): fake_questionnaire_store.answer_store = AnswerStore( [Answer("GHI", "String test + !").to_dict()]) question = { "id": "question-2", "answers": [{ "id": "GHI", "type": "TextField" }] } questionnaire = make_schema("0.0.1", "section-1", "group-1", "block-1", question) full_routing_path = [ RoutingPath(["block-1"], section_id="section-1", list_item_id=None) ] answer_object = convert_answers( QuestionnaireSchema(questionnaire), fake_questionnaire_store, full_routing_path, SUBMITTED_AT, ) assert not answer_object["data"]
def test_routing_path_with_conditional_path(self): schema = load_schema_from_name("test_new_routing_number_equals") section_id = schema.get_section_id_for_block_id("number-question") expected_path = RoutingPath( ["number-question", "correct-answer"], section_id="default-section", ) answer = Answer(answer_id="answer", value=123) answer_store = AnswerStore() answer_store.add_or_update(answer) progress_store = ProgressStore([{ "section_id": "default-section", "list_item_id": None, "status": CompletionStatus.COMPLETED, "block_ids": ["number-question"], }]) path_finder = PathFinder( schema, answer_store, self.list_store, progress_store, self.metadata, self.response_metadata, ) routing_path = path_finder.routing_path(section_id=section_id) self.assertEqual(routing_path, expected_path)
def test_unit_answer(fake_questionnaire_store): full_routing_path = [ RoutingPath(["unit-block"], section_id="section-1", list_item_id=None) ] fake_questionnaire_store.answer_store = AnswerStore( [Answer("unit-answer", 10).to_dict()]) question = { "id": "unit-question", "answers": [{ "id": "unit-answer", "type": "Unit", "q_code": "1" }], } questionnaire = make_schema("0.0.1", "section-1", "unit-block", "unit-block", question) # When answer_object = convert_answers( QuestionnaireSchema(questionnaire), fake_questionnaire_store, full_routing_path, SUBMITTED_AT, ) # Then assert len(answer_object["data"]) == 1 assert answer_object["data"]["1"] == "10"
def test_routing_path_empty_routing_rules(self): schema = load_schema_from_name("test_checkbox") section_id = schema.get_section_id_for_block_id("mandatory-checkbox") expected_path = RoutingPath( [ "mandatory-checkbox", "non-mandatory-checkbox", "single-checkbox" ], section_id="default-section", ) answer_1 = Answer(answer_id="mandatory-checkbox-answer", value="Cheese") answer_2 = Answer(answer_id="non-mandatory-checkbox-answer", value="deep pan") answer_3 = Answer(answer_id="single-checkbox-answer", value="Estimate") answer_store = AnswerStore() answer_store.add_or_update(answer_1) answer_store.add_or_update(answer_2) answer_store.add_or_update(answer_3) progress_store = ProgressStore([{ "section_id": "default-section", "list_item_id": None, "status": CompletionStatus.COMPLETED, "block_ids": ["mandatory-checkbox"], }]) path_finder = PathFinder(schema, answer_store, self.list_store, progress_store, self.metadata) routing_path = path_finder.routing_path(section_id=section_id) self.assertEqual(routing_path, expected_path)
def test_answer_with_float(fake_questionnaire_store): fake_questionnaire_store.answer_store = AnswerStore( [Answer("GHI", 10.02).to_dict()]) question = { "id": "question-2", "answers": [{ "id": "GHI", "type": "TextField", "q_code": "003" }], } questionnaire = make_schema("0.0.1", "section-1", "group-1", "block-1", question) full_routing_path = [ RoutingPath(["block-1"], section_id="section-1", list_item_id=None) ] answer_object = convert_answers( QuestionnaireSchema(questionnaire), fake_questionnaire_store, full_routing_path, SUBMITTED_AT, ) # Check the converter correctly assert answer_object["data"]["003"] == "10.02"
def test_textarea_answer(fake_questionnaire_store): full_routing_path = [RoutingPath(["textarea-block"], section_id="section-1")] answers = AnswerStore( [Answer("textarea-answer", "This is an example text!").to_dict()] ) fake_questionnaire_store.answer_store = answers questionnaire = make_schema( "0.0.3", "section-1", "textarea-group", "textarea-block", { "id": "textarea-question", "answers": [{"id": "textarea-answer", "type": "TextArea"}], }, ) answer_object = convert_answers( QuestionnaireSchema(questionnaire), fake_questionnaire_store, full_routing_path, SUBMITTED_AT, ) assert len(answer_object["data"]["answers"]) == 1 assert answer_object["data"]["answers"][0].value == "This is an example text!"
def test_dropdown_answer(fake_questionnaire_store): full_routing_path = [RoutingPath(["dropdown-block"], section_id="section-1")] answers = AnswerStore([Answer("dropdown-answer", "Rugby is better!").to_dict()]) fake_questionnaire_store.answer_store = answers questionnaire = make_schema( "0.0.3", "section-1", "dropdown-group", "dropdown-block", { "id": "dropdown-question", "answers": [ { "id": "dropdown-answer", "type": "Dropdown", "options": [ {"label": "Liverpool", "value": "Liverpool"}, {"label": "Chelsea", "value": "Chelsea"}, {"label": "Rugby is better!", "value": "Rugby is better!"}, ], } ], }, ) answer_object = convert_answers( QuestionnaireSchema(questionnaire), fake_questionnaire_store, full_routing_path ) # Then assert len(answer_object["data"]["answers"]) == 1 assert answer_object["data"]["answers"][0].value == "Rugby is better!"
def test_month_year_date_answer(fake_questionnaire_store): full_routing_path = [RoutingPath(["date-block"], section_id="section-1")] answers = AnswerStore( [ Answer("single-date-answer", "01-01-1990").to_dict(), Answer("month-year-answer", "01-1990").to_dict(), ] ) fake_questionnaire_store.answer_store = answers questionnaire = make_schema( "0.0.3", "section-1", "date-group", "date-block", { "id": "month-year-question", "answers": [{"id": "month-year-answer", "type": "MonthYearDate"}], }, ) answer_object = convert_answers( QuestionnaireSchema(questionnaire), fake_questionnaire_store, full_routing_path, SUBMITTED_AT, ) assert len(answer_object["data"]["answers"]) == 1 assert answer_object["data"]["answers"][0].value == "01-1990"
def test_primary_person_not_in_payload_when_not_answered(fake_questionnaire_store): routing_path = [ RoutingPath( ["list-collector", "next-interstitial", "another-list-collector-block"], section_id="section-1", ) ] answer_objects = [ {"answer_id": "first-name", "value": "1", "list_item_id": "xJlKBy"}, {"answer_id": "last-name", "value": "1", "list_item_id": "xJlKBy"}, {"answer_id": "first-name", "value": "2", "list_item_id": "RfAGDc"}, {"answer_id": "last-name", "value": "2", "list_item_id": "RfAGDc"}, {"answer_id": "anyone-else", "value": "No"}, {"answer_id": "another-anyone-else", "value": "No"}, {"answer_id": "extraneous-answer", "value": "Bad", "list_item_id": "123"}, ] answers = AnswerStore(answer_objects) list_store = ListStore( existing_items=[{"name": "people", "items": ["xJlKBy", "RfAGDc"]}] ) fake_questionnaire_store.answer_store = answers fake_questionnaire_store.list_store = list_store schema = load_schema_from_name("test_list_collector") output = convert_answers(schema, fake_questionnaire_store, routing_path) data_dict = json_loads(json_dumps(output["data"]["lists"])) assert "primary_person" not in data_dict[0]
def test_routing_path(self): schema = load_schema_from_name("test_summary") section_id = schema.get_section_id_for_block_id("dessert") expected_path = RoutingPath( ["radio", "dessert", "dessert-confirmation", "numbers", "summary"], section_id="default-section", ) progress_store = ProgressStore([{ "section_id": "default-section", "list_item_id": None, "status": CompletionStatus.COMPLETED, "block_ids": [ "radio", "dessert", "dessert-confirmation", "numbers", ], }]) path_finder = PathFinder(schema, self.answer_store, self.list_store, progress_store, self.metadata) routing_path = path_finder.routing_path(section_id=section_id) self.assertEqual(routing_path, expected_path)
def test_convert_payload_0_0_3_multiple_answers(fake_questionnaire_store): full_routing_path = [RoutingPath(["crisps"], section_id="section-1")] answers = AnswerStore( [Answer("crisps-answer", ["Ready salted", "Sweet chilli"]).to_dict()] ) fake_questionnaire_store.answer_store = answers questionnaire = make_schema( "0.0.3", "section-1", "favourite-food", "crisps", { "id": "crisps-question", "answers": [ { "id": "crisps-answer", "type": "Checkbox", "options": [ {"label": "Ready salted", "value": "Ready salted"}, {"label": "Sweet chilli", "value": "Sweet chilli"}, {"label": "Cheese and onion", "value": "Cheese and onion"}, ], } ], }, ) # When answer_object = convert_answers( QuestionnaireSchema(questionnaire), fake_questionnaire_store, full_routing_path ) # Then assert len(answer_object["data"]["answers"]) == 1 assert answer_object["data"]["answers"][0].value == ["Ready salted", "Sweet chilli"]
def test_routing_path_should_not_skip_group(self): # Given schema = load_schema_from_name("test_skip_condition_group") section_id = schema.get_section_id_for_block_id("do-you-want-to-skip") answer_store = AnswerStore() answer_store.add_or_update( Answer(answer_id="do-you-want-to-skip-answer", value="No")) progress_store = ProgressStore([{ "section_id": "default-section", "list_item_id": None, "status": CompletionStatus.COMPLETED, "block_ids": ["do-you-want-to-skip"], }]) # When path_finder = PathFinder(schema, answer_store, self.list_store, progress_store, self.metadata) routing_path = path_finder.routing_path(section_id=section_id) # Then expected_routing_path = RoutingPath( [ "do-you-want-to-skip", "should-skip", "last-group-block", "summary" ], section_id="default-section", ) with patch("app.questionnaire.path_finder.evaluate_skip_conditions", return_value=False): self.assertEqual(routing_path, expected_routing_path)
def test_new_routing_basic_and_conditional_path(self): # Given schema = load_schema_from_name("test_new_routing_number_equals") section_id = schema.get_section_id_for_block_id("number-question") expected_path = RoutingPath( ["number-question", "correct-answer"], section_id="default-section", ) answer_1 = Answer(answer_id="answer", value=123) answer_store = AnswerStore() answer_store.add_or_update(answer_1) # When path_finder = PathFinder( schema, answer_store, self.list_store, self.progress_store, self.metadata, self.response_metadata, ) routing_path = path_finder.routing_path(section_id=section_id) # Then self.assertEqual(routing_path, expected_path)