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_minimum_and_maximum_offset_dates(self, mock1): test_metadata = {'date': '2018-02-20'} store = AnswerStore() test_answer_id = Answer( answer_id='date', answer_instance=1, group_instance=0, value='2018-03-20', ) store.add_or_update(test_answer_id) answer = { 'id': 'date_answer', 'type': 'Date', 'minimum': { 'meta': 'date', 'offset_by': { 'days': -10 } }, 'maximum': { 'answer_id': 'date', 'offset_by': { 'years': 1 } } } offset_dates = get_dates_for_single_date_period_validation( answer, store, metadata=test_metadata) self.assertEqual(offset_dates, (convert_to_datetime('2018-02-10'), convert_to_datetime('2019-03-20')))
def test_bespoke_message_for_sum_validation(self): store = AnswerStore() answer_total = Answer(answer_id="total-answer", value=10) store.add_or_update(answer_total) with self.app_request_context(): schema = load_schema_from_name( "test_sum_equal_validation_against_total") question_schema = schema.get_block("breakdown-block").get( "question") question_schema["validation"] = { "messages": { "TOTAL_SUM_NOT_EQUALS": "Test Message" } } data = {"breakdown-1": "3", "breakdown-2": "5"} form = generate_form(schema, question_schema, store, metadata=None, formdata=data) with patch( "app.questionnaire.questionnaire_schema.QuestionnaireSchema.get_all_questions_for_block", return_value=[question_schema], ): form.validate() self.assertIn(form.question_errors["breakdown-question"], "Test Message")
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 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_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_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_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_generate_form_with_title_and_no_answer_label(self): """ Checks that the form is still generated when there is no answer label but there is a question title """ store = AnswerStore() conditional_answer = Answer(answer_id="behalf-of-answer", value="chad") store.add_or_update(conditional_answer) with self.app_request_context(): schema = load_schema_from_name("test_title") question_schema = schema.get_block("single-title-block").get( "question") data = {"feeling-answer": "good"} expected_form_data = {"csrf_token": "", "feeling-answer": "good"} with patch("app.questionnaire.path_finder.evaluate_goto", return_value=False): form = generate_form(schema, question_schema, store, metadata={}, formdata=data) form.validate() assert form.data == expected_form_data
def test_routing_ignores_answers_not_on_path(self): when = { 'when': [{ 'id': 'some-answer', 'condition': 'equals', 'value': 'some value' }] } answer_store = AnswerStore({}) answer_store.add_or_update( Answer( answer_id='some-answer', value='some value', group_instance=0, )) routing_path = [Location('test', 0, 'test_block_id')] with patch('app.questionnaire.rules._get_answers_on_path', return_value=answer_store): self.assertTrue( evaluate_when_rules(when['when'], get_schema_mock(), {}, answer_store, 0, None)) with patch('app.questionnaire.rules._is_answer_on_path', return_value=False): self.assertFalse( evaluate_when_rules(when['when'], get_schema_mock(), {}, answer_store, 0, None, routing_path=routing_path))
def test_evaluate_goto_returns_true_when_answer_value_not_equals_any_match_values( self): goto = { "id": "next-question", "when": [{ "id": "my_answers", "condition": "not equals any", "values": ["answer1", "answer2"], }], } answer_store = AnswerStore() answer_store.add_or_update( Answer(answer_id="my_answers", value="answer3")) 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_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 test_meta_comparison_missing(self): # Given goto_rule = { "id": "next-question", "when": [{ "condition": "equals", "meta": "variant_flags.does_not_exist.does_not_exist", "value": True, }], } answer_store = AnswerStore() answer_store.add_or_update(Answer(answer_id="my_answer", value="Yes")) metadata = {"varient_flags": {"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_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_or_update(answer_1) answer_store.add_or_update(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, None) self.assertEqual( 'Multiple answers (2) found evaluating when rule for answer (my_answers)', str(err.exception))
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_or_update( Answer(answer_id='this', value='not correct')) answer_store.add_or_update( 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_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} # When goto = evaluate_goto(goto_rule, get_schema_mock(), metadata, answer_store, 0) # Then self.assertFalse(goto)
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_or_update(Answer(answer_id='this', value='value')) answer_store.add_or_update( 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_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_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.get_list_item_id_for_answer_id = Mock(return_value="123abc") self.assertFalse( evaluate_when_rules( when_rules=when["when"], schema=schema, metadata={}, answer_store=answer_store, list_store=ListStore(), current_location=current_location, ))
def test_get_referenced_offset_value_with_list_item_id(app, schema_mock): list_item_id = "abcde" answer_store = AnswerStore() test_answer_id = Answer(answer_id="date", value="2018-03-20", list_item_id=list_item_id) location = Location(section_id="test", list_item_id=list_item_id) answer_store.add_or_update(test_answer_id) answer = { "maximum": { "value": { "identifier": "date", "source": "answers" }, "offset_by": { "months": 1 }, } } handler = DateHandler(answer, answer_store=answer_store, location=location) maximum_date = handler.get_date_value("maximum") assert maximum_date == convert_to_datetime("2018-04-20")
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_do_not_go_to_next_question_for_multiple_answers(self): # Given goto_rule = { "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="No")) current_location = Location(section_id="some-section", block_id="some-block") self.assertFalse( evaluate_goto( goto_rule=goto_rule, schema=get_schema(), metadata={}, answer_store=answer_store, list_store=ListStore(), current_location=current_location, ))
def test_routing_path_with_conditional_path(self): schema = load_schema_from_name("test_routing_number_equals") section_id = schema.get_section_id_for_block_id("number-question") expected_path = RoutingPath( ["number-question", "correct-answer", "summary"], 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 ) routing_path = path_finder.routing_path(section_id=section_id) self.assertEqual(routing_path, expected_path)
def test_multi_calculation(self): store = AnswerStore() answer_total = Answer(answer_id="total-answer", value=10) store.add_or_update(answer_total) with self.app_request_context(): schema = load_schema_from_name( "test_sum_multi_validation_against_total") question_schema = schema.get_block("breakdown-block").get( "question") data = { "breakdown-1": "", "breakdown-2": "", "breakdown-3": "", "breakdown-4": "", } # With no answers question validation should pass form = generate_form(schema, question_schema, store, metadata=None, formdata=data) form.validate() self.assertEqual(len(form.question_errors), 0) # With the data equaling the total question validation should pass data["breakdown-1"] = "10" form = generate_form(schema, question_schema, store, metadata=None, formdata=data) form.validate() self.assertEqual(len(form.question_errors), 0) # With the data not equaling zero or the total, question validation should fail data["breakdown-1"] = "1" form = generate_form(schema, question_schema, store, metadata=None, formdata=data) form.validate() self.assertEqual( form.question_errors["breakdown-question"], schema.error_messages["TOTAL_SUM_NOT_EQUALS"] % dict(total="10"), )
def test_get_referenced_offset_value_for_answer_id(self, mock1): store = AnswerStore() test_answer_id = Answer( answer_id='date', answer_instance=1, group_instance=0, value='2018-03-20', ) store.add_or_update(test_answer_id) answer_maximum = {'answer_id': 'date', 'offset_by': {'months': 1}} value = get_referenced_offset_value(answer_maximum, store, {}) self.assertEqual(value, convert_to_datetime('2018-04-20'))
def test_do_not_go_to_next_question_for_answer(self): # Given goto_rule = { 'id': 'next-question', 'when': [{ 'id': 'my_answer', 'condition': 'equals', 'value': 'Yes' }] } answer_store = AnswerStore({}) answer_store.add_or_update(Answer(answer_id='my_answer', value='No')) self.assertFalse( evaluate_goto(goto_rule, get_schema_mock(), {}, answer_store, 0))
def test_get_next_location_confirmation(self): answer = Answer( answer_id='character-answer', value='Orson Krennic', ) answer_store = AnswerStore() answer_store.add_or_update(answer) schema = load_schema_from_params('0', 'rogue_one') navigator = PathFinder(schema, answer_store, {}, []) with patch('app.questionnaire.rules.evaluate_when_rules', return_value=True): next_location = navigator.get_next_location( Location('rogue-one', 0, 'film-takings')) self.assertEqual('summary', next_location.block_id)
def test_evaluate_goto_returns_true_when_value_not_contained_in_list(self): goto = { 'id': 'next-question', 'when': [{ 'id': 'my_answers', 'condition': 'not contains', 'value': 'answer1' }] } answer_store = AnswerStore({}) answer_store.add_or_update( Answer(answer_id='my_answers', value=['answer2', 'answer3'])) self.assertTrue( evaluate_goto(goto, get_schema_mock(), {}, answer_store, 0))
def test_should_minus_one_from_maximum_repeats(self): questionnaire = { 'survey_id': '021', 'data_version': '0.0.1', 'sections': [{ 'id': 'section1', 'groups': [{ 'id': 'group-1', 'blocks': [{ 'id': 'block-1', 'questions': [{ 'id': 'question-2', 'answers': [{ 'id': 'my_answer', 'type': 'TextField' }] }] }] }] }] } schema = QuestionnaireSchema(questionnaire) # Given repeat = {'answer_id': 'my_answer', 'type': 'answer_count_minus_one'} answer_store = AnswerStore({}) for i in range(27): answer_store.add_or_update( Answer(answer_id='my_answer', value='3', answer_instance=i)) current_path = [Location('group-1', 0, 'block-1')] # When number_of_repeats = evaluate_repeat(repeat, answer_store, schema, current_path) self.assertEqual(number_of_repeats, 24)
def test_routing_ignores_answers_not_on_path(self): when = { "when": [{ "id": "some-answer", "condition": "equals", "value": "some value" }] } answer_store = AnswerStore() answer_store.add_or_update( Answer(answer_id="some-answer", value="some value")) routing_path = [ Location(section_id="some-section", block_id="test_block_id") ] current_location = Location(section_id="some-section", block_id="some-block") self.assertTrue( evaluate_when_rules( when_rules=when["when"], schema=get_schema(), metadata={}, answer_store=answer_store, list_store=ListStore(), current_location=current_location, )) current_location = Location(section_id="some-section", block_id="some-block") with patch("app.questionnaire.rules._is_answer_on_path", return_value=False): self.assertFalse( evaluate_when_rules( when_rules=when["when"], schema=get_schema(), metadata={}, answer_store=answer_store, list_store=ListStore(), current_location=current_location, routing_path_block_ids=routing_path, ))