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_next_location_empty_routing_rules(self): schema = load_schema_from_params('test', 'checkbox') schema.answer_is_in_repeating_group = MagicMock(return_value=False) expected_path = [ Location('checkboxes', 0, 'mandatory-checkbox'), Location('checkboxes', 0, 'non-mandatory-checkbox'), Location('checkboxes', 0, 'summary') ] answer_1 = Answer( answer_id='mandatory-checkbox-answer', value='Cheese', ) answer_2 = Answer( answer_id='non-mandatory-checkbox-answer', value='deep pan', ) answers = AnswerStore() answers.add(answer_1) answers.add(answer_2) path_finder = PathFinder(schema, answer_store=answers, metadata={}, completed_blocks=[]) current_location = expected_path[0] expected_next_location = expected_path[1] next_location = path_finder.get_next_location(current_location=current_location) self.assertEqual(next_location, expected_next_location)
def test_build_answers_repeating_answers(self): # Given self.answer_store.add(Answer( answer_id='answer', value='Value', )) self.answer_store.add( Answer( answer_id='answer', value='Value 2', group_instance=1, )) self.answer_store.add( Answer( answer_id='answer', value='Value 3', group_instance=2, )) answer_schema = {'id': 'answer', 'title': '', 'type': '', 'label': ''} question_schema = { 'id': 'question_id', 'title': 'question_title', 'type': 'RepeatingAnswer', 'answers': [answer_schema] } # When with patch('app.templating.summary.question.get_question_title', return_value=False): question = Question(question_schema, self.answer_store, self.metadata, self.schema) # Then self.assertEqual(len(question.answers), 3)
def test_route_based_on_answer_count(self): schema = load_schema_from_params('test', 'routing_answer_count') answer_group_id = 'first-name' answer_store = AnswerStore({}) answer_store.add(Answer( answer_id=answer_group_id, answer_instance=0, value='alice', )) answer_store.add(Answer( answer_id=answer_group_id, answer_instance=1, value='bob', )) completed_blocks = [ Location('multiple-questions-group', 0, 'household-composition') ] expected_next_location = Location('group-equal-2', 0, 'group-equal-2-block') should_not_be_present = Location('group-less-than-2', 0, 'group-less-than-2-block') path_finder = PathFinder(schema, answer_store, metadata={}, completed_blocks=completed_blocks) path = path_finder.build_path() self.assertNotIn(should_not_be_present, path) self.assertIn(expected_next_location, path)
def test_get_next_location_summary(self): schema = load_schema_from_params('0', 'star_wars') schema.answer_is_in_repeating_group = MagicMock(return_value=False) answer_1 = Answer( answer_id='choose-your-side-answer', value='Light Side' ) answer_2 = Answer( answer_id='light-side-pick-ship-answer', value='No', ) answers = AnswerStore() answers.add(answer_1) answers.add(answer_2) path_finder = PathFinder(schema, answer_store=answers, metadata={}, completed_blocks=[]) current_location = Location('star-wars', 0, 'star-wars-trivia-part-2') next_location = path_finder.get_next_location(current_location=current_location) expected_next_location = Location('star-wars', 0, 'star-wars-trivia-part-3') self.assertEqual(expected_next_location, next_location) current_location = expected_next_location next_location = path_finder.get_next_location(current_location=current_location) expected_next_location = Location('star-wars', 0, 'summary') self.assertEqual(expected_next_location, next_location)
def test_evaluate_when_rules_condition_is_not_met(self): # Given answer_1 = Answer( answer_id='my_answers', answer_instance=0, group_instance=0, value=10, ) answer_2 = Answer( answer_id='my_answers', answer_instance=1, group_instance=0, value=20, ) answer_store = AnswerStore({}) answer_store.add(answer_1) answer_store.add(answer_2) when = { 'id': 'next-question', 'when': [ { 'id': 'my_answers', 'condition': 'not set', 'value': '2' } ] } # When with self.assertRaises(Exception) as err: evaluate_when_rules(when['when'], get_schema_mock(), None, answer_store, 0) self.assertEqual('Multiple answers (2) found evaluating when rule for answer (my_answers)', str(err.exception))
def test_remove_empty_household_members_middle_name_only_not_stored(self): schema = load_schema_from_params('census', 'household') unanswered = [ Answer(group_instance=0, answer_id='first-name', answer_instance=0, value=''), Answer(group_instance=0, answer_id='middle-names', answer_instance=0, value='should not be saved'), Answer(group_instance=0, answer_id='last-name', answer_instance=0, value='') ] for answer in unanswered: self.question_store.answer_store.add_or_update(answer) remove_empty_household_members_from_answer_store( self.question_store.answer_store, schema) for answer in unanswered: self.assertIsNone(self.question_store.answer_store.find(answer))
def test_next_location_empty_routing_rules(self): survey = load_schema_file("test_checkbox.json") expected_path = [ Location("checkboxes", 0, 'introduction'), Location("checkboxes", 0, 'mandatory-checkbox'), Location("checkboxes", 0, 'non-mandatory-checkbox'), Location("checkboxes", 0, 'summary') ] answer_1 = Answer( group_id="checkboxes", block_id="mandatory-checkbox", answer_id="mandatory-checkbox-answer", value="Cheese", ) answer_2 = Answer( group_id="checkboxes", block_id="non-mandatory-checkbox", answer_id="non-mandatory-checkbox-answer", value="deep pan", ) answers = AnswerStore() answers.add(answer_1) answers.add(answer_2) path_finder = PathFinder(survey, answer_store=answers) current_location = expected_path[1] expected_next_location = expected_path[2] next_location = path_finder.get_next_location(current_location=current_location) self.assertEqual(next_location, expected_next_location)
def update_questionnaire_store_with_form_data(questionnaire_store, location, answer_dict): survey_answer_ids = SchemaHelper.get_answer_ids_for_location(g.schema_json, location) for answer_id, answer_value in answer_dict.items(): if answer_id in survey_answer_ids or location.block_id == 'household-composition': answer = None # Dates are comprised of 3 string values if isinstance(answer_value, dict): is_day_month_year = 'day' in answer_value and 'month' in answer_value is_month_year = 'year' in answer_value and 'month' in answer_value if is_day_month_year and answer_value['day'] and answer_value['month']: date_str = "{:02d}/{:02d}/{}".format( int(answer_value['day']), int(answer_value['month']), answer_value['year'], ) answer = Answer(answer_id=answer_id, value=date_str, location=location) elif is_month_year and answer_value['month']: date_str = "{:02d}/{}".format(int(answer_value['month']), answer_value['year']) answer = Answer(answer_id=answer_id, value=date_str, location=location) elif answer_value != 'None' and answer_value is not None: # Necessary because default select casts to string value 'None' answer = Answer(answer_id=answer_id, value=answer_value, location=location) if answer: questionnaire_store.answer_store.add_or_update(answer) if location not in questionnaire_store.completed_blocks: questionnaire_store.completed_blocks.append(location)
def test_routing_basic_and_conditional_path(self): survey = load_schema_file("0_star_wars.json") expected_path = [ Location("star-wars", 0, "introduction"), Location("star-wars", 0, "choose-your-side-block"), Location("star-wars", 0, "dark-side-pick-character-ship"), Location("star-wars", 0, "light-side-ship-type"), Location("star-wars", 0, "star-wars-trivia"), Location("star-wars", 0, "star-wars-trivia-part-2"), Location("star-wars", 0, "star-wars-trivia-part-3"), Location("star-wars", 0, "summary"), ] answer_1 = Answer( group_id="star-wars", block_id="choose-your-side-block", answer_id="choose-your-side-answer", value="Dark Side" ) answer_2 = Answer( group_id="star-wars", block_id="dark-side-pick-character-ship", answer_id="dark-side-pick-ship-answer", value="Can I be a pain and have a goodies ship", ) answers = AnswerStore() answers.add(answer_1) answers.add(answer_2) path_finder = PathFinder(survey, answer_store=answers) routing_path = path_finder.get_routing_path() self.assertEqual(routing_path, expected_path)
def test_previous_with_conditional_path_alternative(self): survey = load_schema_file("0_star_wars.json") expected_path = [ Location("star-wars", 0, "choose-your-side-block"), Location("star-wars", 0, "light-side-pick-character-ship"), Location("star-wars", 0, "star-wars-trivia"), Location("star-wars", 0, "star-wars-trivia-part-2"), Location("star-wars", 0, "star-wars-trivia-part-3"), ] current_location = expected_path[2] expected_previous_location = expected_path[1] answer_1 = Answer( group_id="star-wars", block_id="choose-your-side-block", answer_id="choose-your-side-answer", value="Light Side" ) answer_2 = Answer( group_id="star-wars", block_id="light-side-pick-character-ship", answer_id="light-side-pick-ship-answer", value="No", ) answers = AnswerStore() answers.add(answer_1) answers.add(answer_2) path_finder = PathFinder(survey, answer_store=answers) self.assertEqual(path_finder.get_previous_location(current_location=current_location), expected_previous_location)
def test_filter_chaining_escaped(self): self.store.add(Answer( answer_id='1', answer_instance=0, group_instance=1, value=25, )) self.store.add(Answer( answer_id='2', answer_instance=0, group_instance=1, value="'Twenty Five'", )) escaped = self.store.filter(answer_ids=['2']).escaped() self.assertEqual(len(escaped.answers), 1) self.assertEqual(escaped[0]['value'], ''Twenty Five'') # answers in the store have not been escaped self.assertEqual(self.store[0]['value'], 25) self.assertEqual(self.store[1]['value'], "'Twenty Five'") values = self.store.filter(answer_ids=['2']).escaped().values() self.assertEqual(len(values), 1) self.assertEqual(values[0], ''Twenty Five'')
def test_escaped(self): self.store.add(Answer( answer_id='1', answer_instance=0, group_instance=1, value=25, )) self.store.add(Answer( answer_id='2', answer_instance=0, group_instance=1, value="'Twenty Five'", )) escaped = self.store.escaped() self.assertEqual(len(escaped.answers), 2) self.assertEqual(escaped[0]['value'], 25) self.assertEqual(escaped[1]['value'], ''Twenty Five'') # answers in the store have not been escaped self.assertEqual(self.store.answers[0]['value'], 25) self.assertEqual(self.store.answers[1]['value'], "'Twenty Five'")
def test_updates_answer(self): answer_1 = Answer( answer_id='4', answer_instance=1, group_instance=1, value=25, ) answer_2 = Answer( answer_id='4', answer_instance=1, group_instance=1, value=65, ) self.store.add(answer_1) self.store.update(answer_2) self.assertEqual(len(self.store.answers), 1) store_match = self.store.filter( answer_ids=['4'], answer_instance=1, group_instance=1, ) self.assertEqual(store_match.answers, [answer_2.__dict__])
def test_evaluate_skip_condition_returns_true_when_more_than_one_rule_is_true(self): # Given skip_conditions = [ { 'when': [ { 'id': 'this', 'condition': 'equals', 'value': 'value' } ] }, { 'when': [ { 'id': 'that', 'condition': 'equals', 'value': 'other value' } ] } ] answer_store = AnswerStore({}) answer_store.add(Answer(answer_id='this', value='value')) answer_store.add(Answer(answer_id='that', value='other value')) # When condition = evaluate_skip_conditions(skip_conditions, get_schema_mock(), {}, answer_store) # Then self.assertTrue(condition)
def test_build_answers_puts_answers_in_repeating_group(self): # Given self.answer_store.add( Answer( answer_id='first_name', value='Bloggs', answer_instance=1, )) self.answer_store.add( Answer( answer_id='first_name', value='Joe', answer_instance= 0, # answer_instance deliberately in inverse order )) answer_ids_on_path = ['first_name'] # When self.schema.is_repeating_answer_type = MagicMock(return_value=True) context_answers = _build_answers(self.answer_store, self.schema, answer_ids_on_path) # Then self.assertEqual(len(context_answers), 1) self.assertEqual(context_answers['first_name'], ['Joe', 'Bloggs'])
def test_evaluate_skip_condition_returns_false_when_both_or_rules_false(self): # Given skip_conditions = [ { 'when': [ { 'id': 'this', 'condition': 'equals', 'value': 'value' } ] }, { 'when': [ { 'id': 'that', 'condition': 'equals', 'value': 'other value' } ] } ] answer_store = AnswerStore({}) answer_store.add(Answer(answer_id='this', value='not correct')) answer_store.add(Answer(answer_id='that', value='not correct')) # When condition = evaluate_skip_conditions(skip_conditions, get_schema_mock(), {}, answer_store) # Then self.assertFalse(condition)
def test_build_answers_context_repeating_answers(self): # Given self.answer_store.add( Answer( answer_id='full_name_answer', value='Person One', )) self.answer_store.add( Answer( answer_id='full_name_answer', value='Person Two', answer_instance=1, )) self.answer_store.add( Answer(answer_id='full_name_answer', value='Person One', answer_instance=2)) answer_ids_on_path = ['full_name_answer'] # When self.schema.is_repeating_answer_type = MagicMock(return_value=True) context_answers = _build_answers(self.answer_store, self.schema, answer_ids_on_path) # Then self.assertIsInstance(context_answers['full_name_answer'], list) self.assertEqual(len(context_answers['full_name_answer']), 3) self.assertEqual(len(context_answers), 1)
def test_updating_questionnaire_store_specific_group(self): schema = load_schema_from_params('test', 'repeating_household_routing') answers = [ Answer(group_instance=0, answer_id='first-name', answer_instance=0, value='Joe'), Answer(group_instance=0, answer_id='last-name', answer_instance=0, value='Bloggs'), Answer(group_instance=0, answer_id='date-of-birth-answer', answer_instance=0, value='2016-03-12'), Answer(group_instance=1, answer_id='date-of-birth-answer', answer_instance=0, value='2018-01-01') ] for answer in answers: self.question_store.answer_store.add_or_update(answer) answer_form_data = {'date-of-birth-answer': None} location = Location('household-member-group', 1, 'date-of-birth') with self._application.test_request_context(): update_questionnaire_store_with_form_data(self.question_store, location, answer_form_data, schema) self.assertIsNone(self.question_store.answer_store.find(answers[3])) for answer in answers[:2]: self.assertIsNotNone(self.question_store.answer_store.find(answer))
def test_maps_and_filters_answers(self): questionnaire = { 'sections': [{ 'id': 'section1', 'groups': [ { 'id': 'group1', 'blocks': [ { 'id': 'block1', 'questions': [{ 'id': 'question1', 'answers': [ { 'id': 'answer1', 'type': 'TextArea' } ] }] }, { 'id': 'block2', 'questions': [{ 'id': 'question2', 'answers': [ { 'id': 'answer2', 'type': 'TextArea' } ] }] }] }] }] } schema = QuestionnaireSchema(questionnaire) answer_1 = Answer( answer_id='answer2', answer_instance=1, group_instance_id='group-1', group_instance=1, value=25, ) answer_2 = Answer( answer_id='answer1', answer_instance=1, group_instance_id='group-1', group_instance=1, value=65, ) self.store.add_or_update(answer_1) self.store.add_or_update(answer_2) expected_answers = { 'answer1_1': 65 } self.assertEqual(get_mapped_answers(schema, self.store, block_id='block1', group_instance=1, group_instance_id='group-1'), expected_answers)
def test_repeating_groups_no_of_answers_minus_one(self): survey = load_schema_file("test_repeating_household.json") # Default is to count answers, so switch to using value survey['groups'][-1]['routing_rules'][0]['repeat'][ 'type'] = 'answer_count_minus_one' expected_path = [ Location("multiple-questions-group", 0, "household-composition"), Location("repeating-group", 0, "repeating-block-1"), Location("repeating-group", 0, "repeating-block-2"), ] answer = Answer(group_id="multiple-questions-group", group_instance=0, answer_instance=0, answer_id="first-name", block_id="household-composition", value="Joe Bloggs") answer_2 = Answer(group_id="multiple-questions-group", group_instance=0, answer_instance=1, answer_id="first-name", block_id="household-composition", value="Sophie Bloggs") answers = AnswerStore() answers.add(answer) answers.add(answer_2) path_finder = PathFinder(survey, answer_store=answers) self.assertEqual(expected_path, path_finder.get_routing_path())
def test_answer_count_when_rule_equal_2(self): """Assert that an `answer_count` can be used in a when block and the value is correctly matched """ answer_group_id = 'repeated-answer' when = [{ 'type': 'answer_count', 'answer_ids': [answer_group_id], 'condition': 'equals', 'value': 2, }] answer_store = AnswerStore({}) answer_store.add_or_update( Answer( answer_id=answer_group_id, group_instance=0, group_instance_id='group-1-0', value=10, )) answer_store.add_or_update( Answer( answer_id=answer_group_id, group_instance=1, group_instance_id='group-1-1', value=20, )) self.assertTrue( evaluate_when_rules(when, get_schema_mock(), {}, answer_store, 0, None))
def test_routing_basic_and_conditional_path(self): # Given schema = load_schema_from_params('0', 'star_wars') expected_path = [ Location('star-wars', 0, 'introduction'), Location('star-wars', 0, 'choose-your-side-block'), Location('star-wars', 0, 'dark-side-pick-character-ship'), Location('star-wars', 0, 'light-side-ship-type'), Location('star-wars', 0, 'star-wars-trivia'), Location('star-wars', 0, 'star-wars-trivia-part-2'), Location('star-wars', 0, 'star-wars-trivia-part-3'), Location('star-wars', 0, 'summary'), ] answer_1 = Answer( answer_id='choose-your-side-answer', value='Dark Side' ) answer_2 = Answer( answer_id='dark-side-pick-ship-answer', value='Can I be a pain and have a goodies ship', ) answers = AnswerStore() answers.add(answer_1) answers.add(answer_2) schema.answer_is_in_repeating_group = MagicMock(return_value=False) # When path_finder = PathFinder(schema, answer_store=answers, metadata={}, completed_blocks=[]) routing_path = path_finder.get_full_routing_path() # Then self.assertEqual(routing_path, expected_path)
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", "summary"], 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_store = AnswerStore() answer_store.add_or_update(answer_1) answer_store.add_or_update(answer_2) 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_previous_with_conditional_path_alternative(self): schema = load_schema_from_params('0', 'star_wars') schema.answer_is_in_repeating_group = MagicMock(return_value=False) expected_path = [ Location('star-wars', 0, 'choose-your-side-block'), Location('star-wars', 0, 'light-side-pick-character-ship'), Location('star-wars', 0, 'star-wars-trivia'), Location('star-wars', 0, 'star-wars-trivia-part-2'), Location('star-wars', 0, 'star-wars-trivia-part-3'), ] current_location = expected_path[2] expected_previous_location = expected_path[1] answer_1 = Answer( answer_id='choose-your-side-answer', value='Light Side' ) answer_2 = Answer( answer_id='light-side-pick-ship-answer', value='No', ) answers = AnswerStore() answers.add(answer_1) answers.add(answer_2) path_finder = PathFinder(schema, answer_store=answers, metadata={}, completed_blocks=[]) self.assertEqual(path_finder.get_previous_location(current_location=current_location), expected_previous_location)
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_repeating_group_block_skip_correct_if_independent_answer_is_not_repeating_but_causes_a_skip(self): """ tests blocks are correctly added to path in the case where the blocks in a repeating group have skip conditions and those skip conditions are dependant on a non repeating answer which causes a skip condition to return true. """ # Given independent_answer = '3' expected_path = [ Location('about-household-group', 0, 'household-composition'), Location('independent-answer-group', 0, 'non-repeating-question-block'), Location('questionnaire-completed', 0, 'confirmation') ] schema = load_schema_from_params('test', 'skip_conditions_from_repeating_group_based_on_non_repeating_answer') answer_store = AnswerStore() # Set up some first names answer_store.add(Answer(answer_id='first-name', value='aaa', group_instance=0)) answer_store.add(Answer(answer_id='first-name', value='bbb', group_instance=1)) answer_store.add(Answer(answer_id='first-name', value='ccc', group_instance=2)) # Set up the independent answer answer_store.add(Answer(answer_id='an-independent-answer', value=independent_answer, group_instance=0)) path_finder = PathFinder(schema, answer_store=answer_store, metadata={}, completed_blocks=[]) # When with patch('app.questionnaire.path_finder.evaluate_skip_conditions', return_value=True): new_path = path_finder.get_full_routing_path() # Then self.assertEqual(expected_path, new_path)
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 setUp(self): self.store = AnswerStore() answer1 = Answer( answer_id='set-minimum', answer_instance=1, group_instance=1, value=10, ) answer2 = Answer( answer_id='set-maximum', answer_instance=1, group_instance=1, value=20, ) answer3 = Answer( answer_id='set-maximum-cat', answer_instance=1, group_instance=1, value='cat', ) self.store.add(answer1) self.store.add(answer2) self.store.add(answer3)
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")