def test_transform_variants_with_question_variants(question_variant_schema): schema = QuestionnaireSchema(question_variant_schema) answer_store = AnswerStore({}) answer_store.add_or_update(Answer(answer_id="when-answer", value="no")) metadata = {} block = schema.get_block("block1") section_id = schema.get_section_id_for_block_id(block["id"]) transformed_block = transform_variants( block, schema, metadata, answer_store, ListStore({}), Location(section_id=section_id, block_id=block["id"]), ) compare_transformed_block(block, transformed_block, "Question 1, No") answer_store.add_or_update(Answer(answer_id="when-answer", value="yes")) transformed_block = transform_variants( block, schema, metadata, answer_store, ListStore({}), Location(section_id=section_id, block_id=block["id"]), ) compare_transformed_block(block, transformed_block, "Question 1, Yes")
def test_merge_date_range_answers(self): # Given self.answer_store.add_or_update( Answer(answer_id="answer_1", value="13/02/2016")) self.answer_store.add_or_update( Answer(answer_id="answer_2", value="13/09/2016")) first_date_answer_schema = { "id": "answer_1", "label": "From", "type": "date" } second_date_answer_schema = { "id": "answer_2", "label": "To", "type": "date" } question_schema = { "id": "question_id", "title": "question_title", "type": "DateRange", "answers": [first_date_answer_schema, second_date_answer_schema], } # When question = Question(question_schema, self.answer_store, self.schema, None) # Then self.assertEqual(len(question.answers), 1) self.assertEqual(question.answers[0]["value"]["from"], "13/02/2016") self.assertEqual(question.answers[0]["value"]["to"], "13/09/2016", "%d/%m/%Y")
def test_go_to_next_question_for_multiple_answers(self): # Given goto = { "id": "next-question", "when": [ { "id": "my_answer", "condition": "equals", "value": "Yes" }, { "id": "my_other_answer", "condition": "equals", "value": "2" }, ], } answer_store = AnswerStore() answer_store.add_or_update(Answer(answer_id="my_answer", value="Yes")) answer_store.add_or_update( Answer(answer_id="my_other_answer", value="2")) current_location = Location(section_id="some-section", block_id="some-block") self.assertTrue( evaluate_goto( goto_rule=goto, schema=get_schema(), metadata={}, answer_store=answer_store, list_store=ListStore(), current_location=current_location, ))
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_radio_answer_with_numeric_detail_answer_returns_number(self): # Given self.answer_store.add_or_update(Answer(answer_id="answer_1", value="Other")) self.answer_store.add_or_update(Answer(answer_id="child_answer", value=1)) options = [ {"label": 1, "value": 1}, { "label": "Other", "value": "Other", "detail_answer": {"id": "child_answer", "type": "Number"}, }, ] answer_schema = [ { "id": "answer_1", "label": "How many cakes have you had today?", "type": "Radio", "options": options, } ] question_schema = { "id": "question_id", "title": "question_title", "type": "GENERAL", "answers": answer_schema, } # When question = Question(question_schema, self.answer_store, self.schema, None) # Then self.assertEqual(question.answers[0]["value"]["detail_answer_value"], 1)
def test_create_question_with_multiple_answers(self): # Given self.answer_store.add_or_update( Answer(answer_id="answer_1", value="Han")) self.answer_store.add_or_update( Answer(answer_id="answer_2", value="Solo")) first_answer_schema = { "id": "answer_1", "label": "First name", "type": "text" } second_answer_schema = { "id": "answer_2", "label": "Surname", "type": "text" } question_schema = { "id": "question_id", "title": "question_title", "type": "GENERAL", "answers": [first_answer_schema, second_answer_schema], } # When question = Question(question_schema, self.answer_store, self.schema, None) # Then self.assertEqual(len(question.answers), 2) self.assertEqual(question.answers[0]["value"], "Han") self.assertEqual(question.answers[1]["value"], "Solo")
def test_radio_answer_with_detail_answer_returns_the_value(self): # Given self.answer_store.add_or_update( Answer(answer_id="answer_1", value="Other")) self.answer_store.add_or_update( Answer(answer_id="child_answer", value="Test")) options = [{ "label": "Other", "value": "Other", "detail_answer": { "id": "child_answer", "type": "TextField" }, }] answer_schema = [{ "id": "answer_1", "label": "Which side?", "type": "Radio", "options": options, }] question_schema = { "id": "question_id", "title": "question_title", "type": "GENERAL", "answers": answer_schema, } # When question = Question(question_schema, self.answer_store, self.schema, None) # Then self.assertEqual(question.answers[0]["value"]["detail_answer_value"], "Test")
def test_remove_answer_and_block_if_routing_backwards(self): schema = load_schema_from_name("test_confirmation_question") section_id = schema.get_section_id_for_block_id( "confirm-zero-employees-block") # All blocks completed progress_store = ProgressStore([{ "section_id": "default-section", "list_item_id": None, "status": CompletionStatus.COMPLETED, "block_ids": [ "number-of-employees-total-block", "confirm-zero-employees-block", ], }]) answer_store = AnswerStore() number_of_employees_answer = Answer( answer_id="number-of-employees-total", value=0) confirm_zero_answer = Answer(answer_id="confirm-zero-employees-answer", value="No I need to change this") answer_store.add_or_update(number_of_employees_answer) answer_store.add_or_update(confirm_zero_answer) path_finder = PathFinder(schema, answer_store, self.list_store, progress_store, self.metadata) self.assertEqual( len( path_finder.progress_store.get_completed_block_ids( section_id="default-section")), 2, ) self.assertEqual(len(path_finder.answer_store), 2) routing_path = path_finder.routing_path(section_id=section_id) expected_path = RoutingPath( [ "number-of-employees-total-block", "confirm-zero-employees-block", "number-of-employees-total-block", ], section_id="default-section", ) self.assertEqual(routing_path, expected_path) self.assertEqual( path_finder.progress_store.get_completed_block_ids( section_id="default-section"), [ progress_store.get_completed_block_ids( section_id="default-section")[0] ], ) self.assertEqual(len(path_finder.answer_store), 1)
def store_to_serialize(answer_store): answer_store.add_or_update( Answer(answer_id="answer1", value=10, list_item_id="abc123")) answer_store.add_or_update( Answer(answer_id="answer2", value=20, list_item_id="xyz987")) answer_store.add_or_update(Answer(answer_id="answer3", value=30)) return answer_store
def setUp(self): self.store = AnswerStore() answer1 = Answer(answer_id="set-minimum", value=10) answer2 = Answer(answer_id="set-maximum", value=20) answer3 = Answer(answer_id="set-maximum-cat", value="cat") self.store.add_or_update(answer1) self.store.add_or_update(answer2) self.store.add_or_update(answer3)
def test_concatenate_number_and_checkbox_answers(self): answer_separators = {"Newline": "<br>", "Space": " "} for concatenation_type, concatenation_character in answer_separators.items( ): with self.subTest( concatenation_type=concatenation_type, concatenation_character=concatenation_character, ): # Given self.answer_store.add_or_update( Answer(answer_id="age", value=7)) self.answer_store.add_or_update( Answer(answer_id="estimate", value=["This age is an estimate"])) age_answer_schema = { "id": "age", "label": "Enter your age", "mandatory": False, "type": "Number", } checkbox_answer_schema = { "id": "estimate", "mandatory": False, "options": [{ "label": "This age is an estimate", "value": "This age is an estimate", }], "type": "Checkbox", } question_schema = { "id": "question_id", "title": "question_title", "type": "General", "answers": [age_answer_schema, checkbox_answer_schema], "summary": { "concatenation_type": concatenation_type }, } # When question = Question(question_schema, self.answer_store, self.schema, None) # Then self.assertEqual( question.answers[0]["value"], f"7{concatenation_character}This age is an estimate", ) self.assertEqual(len(question.answers), 1)
def basic_answer_store(): answer_store = AnswerStore() answer_store.add_or_update( Answer(answer_id="answer1", value=10, list_item_id="abc123")) answer_store.add_or_update( Answer(answer_id="answer2", value=20, list_item_id="xyz987")) answer_store.add_or_update( Answer(answer_id="another-answer2", value=25, list_item_id="xyz987")) answer_store.add_or_update(Answer(answer_id="answer3", value=30)) answer_store.add_or_update(Answer(answer_id="another-answer3", value=35)) answer_store.add_or_update( Answer(answer_id="answer4", value="<p>abc123</p>")) answer_store.add_or_update( Answer(answer_id="answer5", value=["<p>abc123</p>", "some value"])) answer_store.add_or_update( Answer(answer_id="answer6", value={ "item1": "<p>abc123</p>", "item2": "some value" })) answer_store.add_or_update( Answer(answer_id="to-escape", value="'Twenty Five'")) return answer_store
def test_list_serialisation(store_to_serialize): serialized_store = list(store_to_serialize) assert serialized_store == [ Answer.from_dict( {"answer_id": "answer1", "value": 10, "list_item_id": "abc123"} ), Answer.from_dict( {"answer_id": "answer2", "value": 20, "list_item_id": "xyz987"} ), Answer.from_dict({"answer_id": "answer3", "value": 30, "list_item_id": None}), ]
def test_from_dict(): test_answer = { "answer_id": "test1", "value": "avalue", "list_item_id": "123321" } expected_answer = Answer(answer_id="test1", value="avalue", list_item_id="123321") assert Answer.from_dict(test_answer) == expected_answer
def test_transform_variants_list_collector(list_collector_variant_schema): schema = QuestionnaireSchema(list_collector_variant_schema) answer_store = AnswerStore({}) answer_store.add_or_update(Answer(answer_id="when-answer", value="no")) metadata = {} response_metadata = {} block = schema.get_block("block1") section_id = schema.get_section_id_for_block_id(block["id"]) transformed_block = transform_variants( block, schema, metadata, response_metadata, answer_store, ListStore({}), Location(section_id=section_id, block_id=block["id"]), ) compare_transformed_block( block["add_block"], transformed_block["add_block"], "Add, No" ) compare_transformed_block( block["remove_block"], transformed_block["remove_block"], "Remove, No" ) compare_transformed_block( block["edit_block"], transformed_block["edit_block"], "Edit, No" ) answer_store.add_or_update(Answer(answer_id="when-answer", value="yes")) transformed_block = transform_variants( block, schema, metadata, response_metadata, answer_store, ListStore({}), Location(section_id=section_id, block_id=block["id"]), ) compare_transformed_block( block["add_block"], transformed_block["add_block"], "Add, Yes" ) compare_transformed_block( block["remove_block"], transformed_block["remove_block"], "Remove, Yes" ) compare_transformed_block( block["edit_block"], transformed_block["edit_block"], "Edit, Yes" )
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_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_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_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)
def test_should_not_go_to_next_question_when_second_condition_fails(self): # Given goto_rule = { "id": "next-question", "when": [ { "id": "my_answer", "condition": "equals", "value": "Yes" }, { "condition": "equals", "meta": "sexual_identity", "value": False }, ], } answer_store = AnswerStore() answer_store.add_or_update(Answer(answer_id="my_answer", value="Yes")) metadata = {"sexual_identity": True} current_location = Location(section_id="some-section", block_id="some-block") self.assertFalse( evaluate_goto( goto_rule=goto_rule, schema=get_schema(), metadata=metadata, answer_store=answer_store, list_store=ListStore(), current_location=current_location, ))
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) # Then expected_route = [ { "block_id": "do-you-want-to-skip-block", "group_id": "do-you-want-to-skip-group", }, { "block_id": "summary", "group_id": "should-skip-group" }, ] section_id = schema.get_section_id_for_block_id("summary") pytest.xfail( reason= "Known bug when skipping last group due to summary bundled into it" ) self.assertEqual(path_finder.routing_path(section_id=section_id), expected_route)
def update_relationships_answer( self, relationship_store, relationships_answer_id, ): self._answer_store.add_or_update( Answer(relationships_answer_id, relationship_store.serialize()))
def test_evaluate_when_rule_with_invalid_list_item_id(self): when = { "when": [{ "id": "my_answer", "condition": "equals", "value": "an answer" }] } answer_store = AnswerStore() answer_store.add_or_update( Answer(answer_id="my_answer", value="an answer", list_item_id="abc123")) current_location = Location(section_id="some-section", block_id="some-block", list_item_id="123abc") schema = Mock(get_schema()) schema.is_repeating_answer = Mock(return_value=False) self.assertFalse( evaluate_when_rules( when_rules=when["when"], schema=schema, metadata={}, answer_store=answer_store, list_store=ListStore(), current_location=current_location, ))
def update_answers(self, form_data, list_item_id=None): list_item_id = list_item_id or self._current_location.list_item_id answer_ids_for_question = self._schema.get_answer_ids_for_question( self._current_question ) for answer_id, answer_value in form_data.items(): if answer_id in answer_ids_for_question: answer_value_to_store = ( { key: value for key, value in answer_value.items() if value not in self.EMPTY_ANSWER_VALUES } if isinstance(answer_value, dict) else answer_value ) if answer_value_to_store in self.EMPTY_ANSWER_VALUES: self._answer_store.remove_answer(answer_id, list_item_id) else: answer = Answer( answer_id=answer_id, list_item_id=list_item_id, value=answer_value_to_store, ) self._answer_store.add_or_update(answer)
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_choose_content_to_display(content_variant_schema): schema = QuestionnaireSchema(content_variant_schema) answer_store = AnswerStore({}) answer_store.add_or_update(Answer(answer_id="age-answer", value="18")) metadata = {} block = schema.get_block("block1") section_id = schema.get_section_id_for_block_id(block["id"]) content_to_display = choose_content_to_display( schema.get_block("block1"), schema, metadata, answer_store, ListStore({}), Location(section_id=section_id, block_id=block["id"]), ) assert content_to_display[0]["title"] == "You are over 16" answer_store = AnswerStore({}) content_to_display = choose_content_to_display( schema.get_block("block1"), schema, metadata, answer_store, ListStore({}), Location(section_id=section_id, block_id=block["id"]), ) assert content_to_display[0]["title"] == "You are ageless"
def test_choose_question_to_display(question_variant_schema): schema = QuestionnaireSchema(question_variant_schema) answer_store = AnswerStore({}) answer_store.add_or_update(Answer(answer_id="when-answer", value="yes")) metadata = {} block = schema.get_block("block1") section_id = schema.get_section_id_for_block_id(block["id"]) question_to_display = choose_question_to_display( schema.get_block("block1"), schema, metadata, answer_store, ListStore({}), Location(section_id=section_id, block_id=block["id"]), ) assert question_to_display["title"] == "Question 1, Yes" answer_store = AnswerStore({}) question_to_display = choose_question_to_display( schema.get_block("block1"), schema, metadata, answer_store, ListStore({}), Location(section_id=section_id, block_id=block["id"]), ) assert question_to_display["title"] == "Question 1, No"
def test_do_not_go_to_next_question_for_date_answer(self): goto_rule = { "id": "next-question", "when": [{ "id": "date-answer", "condition": "equals", "date_comparison": { "value": "2018-01" }, }], } answer_store = AnswerStore({}) answer_store.add_or_update( Answer(answer_id="date-answer", value="2018-02-01")) current_location = Location(section_id="some-section", block_id="some-block") self.assertFalse( evaluate_goto( goto_rule=goto_rule, schema=get_schema_mock(), metadata={}, answer_store=answer_store, list_store=ListStore(), current_location=current_location, ))
def relationship_answer_store(): answer_store = AnswerStore() answer_store.add_or_update( Answer( answer_id="relationship-answer", value=[ { "list_item_id": "abc123", "to_list_item_id": "xyz987", "relationship": "Husband or Wife", }, { "list_item_id": "abc123", "to_list_item_id": "123abc", "relationship": "Son or Daughter", }, { "list_item_id": "xyz987", "to_list_item_id": "123abc", "relationship": "Son or Daughter", }, ], ) ) return answer_store
def test_dropdown_selected_option_label(self): # Given options = [ { "label": "Light Side label", "value": "Light Side" }, { "label": "Dark Side label", "value": "Dark Side" }, ] answer_schema = { "id": "answer_1", "label": "Which side?", "type": "Dropdown", "options": options, } question_schema = { "id": "question_id", "title": "question_title", "type": "GENERAL", "answers": [answer_schema], } self.answer_store.add_or_update( Answer(answer_id="answer_1", value="Dark Side")) # When question = Question(question_schema, self.answer_store, self.schema, None) # Then self.assertEqual(question.answers[0]["value"], "Dark Side label")