def test_option_has_other(self): with self.app_request_context(): # STANDARD CHECKBOX schema = load_schema_from_params('test', 'checkbox') block_json = schema.get_block('mandatory-checkbox') form = generate_form(schema, block_json, AnswerStore(), metadata=None, group_instance=0, formdata={}) self.assertFalse( form.option_has_other('mandatory-checkbox-answer', 1)) self.assertTrue( form.option_has_other('mandatory-checkbox-answer', 6)) # MUTUALLY EXCLUSIVE CHECKBOX schema = load_schema_from_params('test', 'checkbox_mutually_exclusive') block_json = schema.get_block('mandatory-checkbox') form = generate_form(schema, block_json, AnswerStore(), metadata=None, group_instance=0, formdata={}) self.assertFalse( form.option_has_other('mandatory-checkbox-answer', 1)) self.assertTrue( form.option_has_other('mandatory-checkbox-answer', 5))
def test_get_other_answer_invalid(self): with self.app_request_context(): # STANDARD CHECKBOX schema = load_schema_from_params('test', 'checkbox') block_json = schema.get_block('mandatory-checkbox') form = generate_form( schema, block_json, AnswerStore(), metadata=None, group_instance=0, formdata={'other-answer-mandatory': 'Some data'}) field = form.get_other_answer('mandatory-checkbox-answer', 4) self.assertEqual(None, field) # MUTUALLY EXCLUSIVE CHECKBOX schema = load_schema_from_params('test', 'checkbox_mutually_exclusive') block_json = schema.get_block('mandatory-checkbox') form = generate_form( schema, block_json, AnswerStore(), metadata=None, group_instance=0, formdata={'other-answer-mandatory': 'Some data'}) field = form.get_other_answer('mandatory-checkbox-answer', 4) self.assertEqual(None, field)
def test_get_parent_options_for_block(self): # STANDARD CHECKBOX schema = load_schema_from_params('test', 'checkbox') parent_options = schema.get_parent_options_for_block('mandatory-checkbox') expected = { 'mandatory-checkbox-answer': { 'index': 6, 'child_answer_id': 'other-answer-mandatory' } } self.assertEqual(parent_options, expected) # MUTUALLY EXCLUSIVE CHECKBOX schema = load_schema_from_params('test', 'checkbox_mutually_exclusive') parent_options = schema.get_parent_options_for_block('mandatory-checkbox') expected = { 'mandatory-checkbox-answer': { 'index': 5, 'child_answer_id': 'other-answer-mandatory' } } self.assertEqual(parent_options, expected)
def test_repeating_skipped_group(self): schema = load_schema_from_params('test', 'navigation_confirmation') routing_path = [ Location('property-details', 0, 'insurance-type'), Location('property-details', 0, 'insurance-address'), Location('property-details', 0, 'property-interstitial'), Location('house-details', 0, 'house-type'), Location('multiple-questions-group', 0, 'household-composition'), Location('repeating-group', 0, 'repeating-block-1'), Location('repeating-group', 0, 'repeating-block-2'), Location('extra-cover', 0, 'extra-cover-block'), Location('extra-cover', 0, 'extra-cover-interstitial'), Location('payment-details', 0, 'credit-card'), Location('payment-details', 0, 'expiry-date'), Location('payment-details', 0, 'security-code'), Location('payment-details', 0, 'security-code-interstitial'), Location('extra-cover-items-group', 0, 'extra-cover-items'), Location('confirmation-group', 0, 'confirmation'), ] progress = Completeness( schema, AnswerStore(), [], routing_path, metadata={}) progress_value = progress.get_state_for_group('repeating-group') self.assertEqual(Completeness.SKIPPED, progress_value)
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_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_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_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_answer_non_repeating_dependency_repeating_validate_all_of_block_and_group_removed( self): """ load a schema with a non repeating independent answer and a repeating one that depends on it validate that when the independent variable is set a call is made to remove all instances of the dependant variables """ # Given schema = load_schema_from_params( 'test', 'titles_repeating_non_repeating_dependency') colour_answer_location = Location('colour-group', 0, 'favourite-colour') colour_answer = {'fav-colour-answer': 'blue'} # When with self._application.test_request_context(): with patch( 'app.data_model.questionnaire_store.QuestionnaireStore.remove_completed_blocks' ) as patch_remove: update_questionnaire_store_with_form_data( self.question_store, colour_answer_location, colour_answer, schema) # Then patch_remove.assert_called_with(group_id='repeating-group', block_id='repeating-block-3')
def test_post_form_for_radio_other_selected(self): with self.app_request_context(): schema = load_schema_from_params('test', 'radio_mandatory_with_mandatory_other') block_json = schema.get_block('radio-mandatory') location = Location('radio', 0, 'radio-mandatory') answer_store = AnswerStore([ { 'answer_id': 'radio-mandatory-answer', 'block_id': 'radio-mandatory', 'value': 'Other', 'answer_instance': 0, }, { 'answer_id': 'other-answer-mandatory', 'block_id': 'radio-mandatory', 'value': 'Other text field value', 'answer_instance': 0, } ]) request_form = MultiDict({ 'radio-mandatory-answer': 'Other', 'other-answer-mandatory': 'Other text field value', }) form = post_form_for_location(schema, block_json, location, answer_store, metadata=None, request_form=request_form) other_text_field = getattr(form, 'other-answer-mandatory') self.assertEqual(other_text_field.data, 'Other text field value')
def get_schema_json(eq_id, form_type): try: schema = load_schema_from_params(eq_id, form_type) return jsonify(schema.json) except FileNotFoundError: return 'Schema Not Found', 404
def test_date_range_to_precedes_from_raises_question_error(self): with self.app_request_context(): schema = load_schema_from_params('test', '0102') block_json = schema.get_block('reporting-period') data = { 'period-from-day': '25', 'period-from-month': '12', 'period-from-year': '2016', 'period-to-day': '24', 'period-to-month': '12', 'period-to-year': '2016' } expected_form_data = { 'csrf_token': '', 'period-from': '2016-12-25', 'period-to': '2016-12-24' } form = generate_form(schema, block_json, AnswerStore(), metadata=None, group_instance=0, formdata=data) form.validate() self.assertEqual(form.data, expected_form_data) self.assertEqual(form.question_errors['reporting-period-question'], schema.error_messages['INVALID_DATE_RANGE'], AnswerStore())
def test_date_yyyy_combined_range_too_large_validation(self): with self.app_request_context(): schema = load_schema_from_params('test', 'date_validation_yyyy_combined') block_json = schema.get_block('date-range-block') data = { 'date-range-from-year': '2016', 'date-range-to-year': '2020' } metadata = { 'ref_p_start_date': '2017-01-01', 'ref_p_end_date': '2017-02-12' } expected_form_data = { 'csrf_token': '', 'date-range-from': '2016', 'date-range-to': '2020' } form = generate_form(schema, block_json, AnswerStore(), metadata, group_instance=0, formdata=data) form.validate() self.assertEqual(form.data, expected_form_data) self.assertEqual( form.question_errors['date-range-question'], schema.error_messages['DATE_PERIOD_TOO_LARGE'] % dict(max='3 years'))
def test_form_date_range_populates_data(self): with self.app_request_context(): schema = load_schema_from_params('test', '0102') block_json = schema.get_block('reporting-period') data = { 'period-from-day': '01', 'period-from-month': '3', 'period-from-year': '2016', 'period-to-day': '31', 'period-to-month': '3', 'period-to-year': '2016' } expected_form_data = { 'csrf_token': '', 'period-from': '2016-03-01', 'period-to': '2016-03-31' } form = generate_form(schema, block_json, AnswerStore(), metadata=None, group_instance=0, formdata=data) self.assertEqual(form.data, expected_form_data)
def test_date_range_valid_period(self): with self.app_request_context(): schema = load_schema_from_params('test', 'date_validation_range') block_json = schema.get_block('date-range-block') data = { 'date-range-from-day': '25', 'date-range-from-month': '12', 'date-range-from-year': '2016', 'date-range-to-day': '26', 'date-range-to-month': '01', 'date-range-to-year': '2017' } expected_form_data = { 'csrf_token': '', 'date-range-from': '2016-12-25', 'date-range-to': '2017-01-26' } form = generate_form(schema, block_json, AnswerStore(), metadata=None, group_instance=0, formdata=data) form.validate() self.assertEqual(form.data, expected_form_data)
def test_update_questionnaire_store_with_form_data(self): schema = load_schema_from_params('test', '0112') location = Location('rsi', 0, 'total-retail-turnover') form_data = { 'total-retail-turnover-answer': '1000', } with self._application.test_request_context(): update_questionnaire_store_with_form_data(self.question_store, location, form_data, schema) self.assertEqual(self.question_store.completed_blocks, [location]) self.assertIn( { 'group_instance_id': None, 'group_instance': 0, 'answer_id': 'total-retail-turnover-answer', 'answer_instance': 0, 'value': '1000' }, self.question_store.answer_store.answers)
def test_build_view_context_for_question(self): # Given g.schema = schema = load_schema_from_params('test', 'titles') block = g.schema.get_block('single-title-block') full_routing_path = [ Location('group', 0, 'single-title-block'), Location('group', 0, 'who-is-answer-block'), Location('group', 0, 'multiple-question-versions-block'), Location('group', 0, 'Summary') ] current_location = Location('group', 0, 'single-title-block') schema_context = _get_schema_context(full_routing_path, current_location, {}, {}, AnswerStore(), g.schema) # When with self._application.test_request_context(): question_view_context = build_view_context('Question', {}, schema, AnswerStore(), schema_context, block, current_location, form=None) # Then self.assertEqual( question_view_context['question_titles']['single-title-question'], 'How are you feeling??')
def test_post_form_for_block_location(self): with self.app_request_context(): schema = load_schema_from_params('test', '0102') block_json = schema.get_block('reporting-period') location = Location(group_id='rsi', group_instance=0, block_id='introduction') form = post_form_for_location(schema, block_json, location, AnswerStore(), metadata=None, request_form={ 'period-from-day': '1', 'period-from-month': '05', 'period-from-year': '2015', 'period-to-day': '1', 'period-to-month': '09', 'period-to-year': '2017', }) self.assertTrue(hasattr(form, 'period-to')) self.assertTrue(hasattr(form, 'period-from')) period_to_field = getattr(form, 'period-to') period_from_field = getattr(form, 'period-from') self.assertIsInstance(period_from_field.month.validators[0], DateRequired) self.assertIsInstance(period_to_field.month.validators[0], DateRequired) self.assertEqual(period_from_field.data, '2015-05-01') self.assertEqual(period_to_field.data, '2017-09-01')
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_title_when_dependencies_are_added_to_dependencies(self): schema = load_schema_from_params('test', 'titles') dependencies = schema.answer_dependencies['behalf-of-answer'] self.assertIn('gender-answer', dependencies) self.assertIn('age-answer', dependencies) self.assertEqual(len(dependencies), 2)
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_post_form_for_household_composition(self): with self.app_request_context(): schema = load_schema_from_params('census', 'household') block_json = schema.get_block('household-composition') location = Location('who-lives-here', 0, 'household-composition') form = post_form_for_location(schema, block_json, location, AnswerStore(), metadata=None, request_form={ 'household-0-first-name': 'Joe', 'household-0-last-name': '', 'household-1-first-name': 'Bob', 'household-1-last-name': 'Seymour', }) self.assertEqual(len(form.household.entries), 2) self.assertEqual(form.household.entries[0].data, { 'first-name': 'Joe', 'middle-names': '', 'last-name': '' }) self.assertEqual(form.household.entries[1].data, { 'first-name': 'Bob', 'middle-names': '', 'last-name': 'Seymour' })
def test_next_location_goto_summary(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, 'introduction'), Location('star-wars', 0, 'choose-your-side-block'), Location('star-wars', 0, 'summary'), ] answer = Answer( group_instance=0, answer_id='choose-your-side-answer', value='I prefer Star Trek', ) answers = AnswerStore() answers.add(answer) path_finder = PathFinder(schema, answer_store=answers, metadata={}, completed_blocks=[]) 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 test_get_form_and_disable_mandatory_answers(self): with self.app_request_context(): schema = load_schema_from_params('test', '0102') block_json = schema.get_block('reporting-period') location = Location(group_id='rsi', group_instance=0, block_id='introduction') form = get_form_for_location(schema, block_json, location, AnswerStore(), metadata=None, disable_mandatory=True) self.assertTrue(hasattr(form, 'period-from')) self.assertTrue(hasattr(form, 'period-to')) period_from_field = getattr(form, 'period-from') period_to_field = getattr(form, 'period-to') self.assertIsInstance(period_from_field.month.validators[0], OptionalForm) self.assertIsInstance(period_to_field.month.validators[0], OptionalForm)
def test_repeating_groups(self): schema = load_schema_from_params('test', 'repeating_household') schema.answer_is_in_repeating_group = MagicMock(return_value=False) # Default is to count answers, so switch to using value schema.json['sections'][-2]['groups'][0]['routing_rules'][0]['repeat']['type'] = 'answer_value' expected_path = [ Location('multiple-questions-group', 0, 'introduction'), Location('multiple-questions-group', 0, 'household-composition'), Location('repeating-group', 0, 'repeating-block-1'), Location('repeating-group', 0, 'repeating-block-2'), Location('repeating-group', 0, 'repeating-block-3'), Location('repeating-group', 1, 'repeating-block-1'), Location('repeating-group', 1, 'repeating-block-2'), Location('repeating-group', 1, 'repeating-block-3'), Location('summary-group', 0, 'summary'), ] answer = Answer( group_instance=0, answer_id='first-name', value='2' ) answers = AnswerStore() answers.add(answer) path_finder = PathFinder(schema, answer_store=answers, metadata={}, completed_blocks=[]) self.assertEqual(expected_path, path_finder.get_full_routing_path())
def test_remove_empty_household_members_partial_answers_are_stored(self): schema = load_schema_from_params('census', 'household') answered = [ Answer(group_instance=0, answer_id='first-name', answer_instance=0, value='Joe'), Answer(group_instance=0, answer_id='middle-names', answer_instance=0, value=''), Answer(group_instance=0, answer_id='last-name', answer_instance=0, value='Bloggs') ] partially_answered = [ Answer(group_instance=0, answer_id='first-name', answer_instance=1, value=''), Answer(group_instance=0, answer_id='middle-names', answer_instance=1, value=''), Answer(group_instance=0, answer_id='last-name', answer_instance=1, value='Last name only'), Answer(group_instance=0, answer_id='first-name', answer_instance=2, value='First name only'), Answer(group_instance=0, answer_id='middle-names', answer_instance=2, value=''), Answer(group_instance=0, answer_id='last-name', answer_instance=2, value='') ] answers = [] answers.extend(answered) answers.extend(partially_answered) for answer in answers: 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 answered: self.assertIsNotNone(self.question_store.answer_store.find(answer)) for answer in partially_answered: self.assertIsNotNone(self.question_store.answer_store.find(answer))
def test_get_routing_path_when_first_block_in_group_skipped(self): # Given schema = load_schema_from_params('test', 'skip_condition_group') answer_store = AnswerStore() answer_store.add(Answer(answer_id='do-you-want-to-skip-answer', value='Yes')) # When path_finder = PathFinder(schema, answer_store=answer_store, metadata={}, completed_blocks=[]) # Then expected_route = [ { 'block_id': 'do-you-want-to-skip-block', 'group_id': 'do-you-want-to-skip-group', 'group_instance': 0 }, { 'block_id': 'summary', 'group_id': 'should-skip-group', 'group_instance': 0 } ] pytest.xfail(reason='Known bug when skipping last group due to summary bundled into it') self.assertEqual(path_finder.get_routing_path('should-skip-group'), expected_route)
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_generate_date_form_validates_single_date_period_with_bespoke_message( self): schema = load_schema_from_params('test', 'date_validation_single') error_messages = schema.error_messages answer = { 'id': 'date-range-from', 'mandatory': True, 'label': 'Period from', 'type': 'Date', 'maximum': { 'value': '2017-06-11', 'offset_by': { 'days': 20 } }, 'validation': { 'messages': { 'SINGLE_DATE_PERIOD_TOO_LATE': 'Test Message' } } } with patch( 'app.questionnaire.questionnaire_schema.QuestionnaireSchema.get_answers_by_id_for_block', return_value=[answer]), self.app_request_context('/'): form = get_date_form(AnswerStore(), {}, answer, error_messages=error_messages) self.assertTrue(hasattr(form, 'day')) self.assertTrue(hasattr(form, 'month')) self.assertTrue(hasattr(form, 'year'))
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))