def test_remove_last_person(self): with self.app_request_context(): form = generate_household_composition_form( self.schema, self.block_json, { 'household-0-first-name': 'Joe', 'household-0-last-name': 'Bloggs', 'household-1-first-name': 'Bob', 'household-1-last-name': 'Seymour', 'household-2-first-name': 'Jane', 'household-2-last-name': 'Seymour', }, metadata=self.metadata, group_instance=0) form.remove_person(2) self.assertEqual(len(form.household.entries), 2) self.assertEqual(form.household.entries[0].data, { 'first-name': 'Joe', 'middle-names': '', 'last-name': 'Bloggs' }) self.assertEqual(form.household.entries[1].data, { 'first-name': 'Bob', 'middle-names': '', 'last-name': 'Seymour' })
def test_remove_first_person(self): form = generate_household_composition_form(self.block_json, { 'household-0-first-name': 'Joe', 'household-0-last-name': 'Bloggs', 'household-1-first-name': 'Bob', 'household-1-middle-names': 'Michael', 'household-1-last-name': 'Seymour', 'household-2-first-name': 'Sophie', 'household-2-last-name': 'Bloggs', 'household-3-first-name': 'Jane', 'household-3-last-name': 'Seymour', }, error_messages=self.error_messages) form.remove_person(0) self.assertEqual(len(form.household.entries), 3) self.assertEqual(form.household.entries[0].data, { 'first-name': 'Bob', 'middle-names': 'Michael', 'last-name': 'Seymour' }) self.assertEqual(form.household.entries[1].data, { 'first-name': 'Sophie', 'middle-names': '', 'last-name': 'Bloggs' }) self.assertEqual(form.household.entries[2].data, { 'first-name': 'Jane', 'middle-names': '', 'last-name': 'Seymour' })
def post_form_for_location(block_json, location, answer_store, request_form, error_messages, disable_mandatory=False): """ Returns the form necessary for the location given a post request, plus any template arguments :param disable_mandatory: Make mandatory answers optional :param error_messages: The default error messages to use within the form :param block_json: The block json :param location: The location which this form is for :param answer_store: The current answer store :param request_form: form, template_args A tuple containing the form for this location and any additional template arguments """ if disable_mandatory: block_json = disable_mandatory_answers(block_json) if location.block_id == 'household-composition': return generate_household_composition_form(block_json, request_form, error_messages), None elif location.block_id in ['relationships', 'household-relationships']: choices = build_relationship_choices(answer_store, location.group_instance) form = generate_relationship_form(block_json, len(choices), request_form, error_messages) return form, {'relation_instances': choices} else: data = clear_other_text_field( request_form, SchemaHelper.get_questions_for_block(block_json)) return generate_form(block_json, data, error_messages), None
def test_remove_last_person(self): with self.test_request_context(): form = generate_household_composition_form( self.block_json, { 'household-0-first-name': 'Joe', 'household-0-last-name': 'Bloggs', 'household-1-first-name': 'Bob', 'household-1-last-name': 'Seymour', 'household-2-first-name': 'Jane', 'household-2-last-name': 'Seymour', }, error_messages=self.error_messages) form.remove_person(2) self.assertEqual(len(form.household.entries), 2) self.assertEqual(form.household.entries[0].data, { 'first-name': 'Joe', 'middle-names': '', 'last-name': 'Bloggs' }) self.assertEqual(form.household.entries[1].data, { 'first-name': 'Bob', 'middle-names': '', 'last-name': 'Seymour' })
def get_form_for_location(schema, block_json, location, answer_store, metadata, disable_mandatory=False): # pylint: disable=too-many-locals """ Returns the form necessary for the location given a get request, plus any template arguments :param schema: schema :param block_json: The block json :param location: The location which this form is for :param answer_store: The current answer store :param metadata: metadata :param disable_mandatory: Make mandatory answers optional :return: form, template_args A tuple containing the form for this location and any additional template arguments """ if disable_mandatory: block_json = disable_mandatory_answers(block_json) if location.block_id == 'household-composition': answer_ids = schema.get_answer_ids_for_block(location.block_id) answers = answer_store.filter(answer_ids, location.group_instance) data = deserialise_composition_answers(answers) return generate_household_composition_form(schema, block_json, data, metadata, location.group_instance) group_instance_id = get_group_instance_id(schema, answer_store, location) if schema.block_has_question_type(location.block_id, 'Relationship'): answer_ids = schema.get_answer_ids_for_block(location.block_id) group = schema.get_group(location.group_id) answers = answer_store.filter(answer_ids, location.group_instance) data = deserialise_relationship_answers(answers) # Relationship block only supports 1 question question = schema.get_question(block_json['questions'][0]['id']) answer_ids = [] repeat_rule = group['routing_rules'][0]['repeat'] if 'answer_ids' in repeat_rule: for answer_id in repeat_rule['answer_ids']: answer_ids.append(answer_id) if 'answer_id' in repeat_rule: answer_ids.append(repeat_rule['answer_id']) relationship_choices = build_relationship_choices(answer_ids, answer_store, location.group_instance, question.get('member_label')) form = generate_relationship_form(schema, block_json, relationship_choices, data, location.group_instance, group_instance_id) return form mapped_answers = get_mapped_answers( schema, answer_store, group_instance=location.group_instance, group_instance_id=group_instance_id, block_id=location.block_id, ) return generate_form(schema, block_json, answer_store, metadata, location.group_instance, group_instance_id, data=mapped_answers)
def post_form_for_location(schema, block_json, location, answer_store, metadata, request_form, disable_mandatory=False): """ Returns the form necessary for the location given a post request, plus any template arguments :param block_json: The block json :param location: The location which this form is for :param answer_store: The current answer store :param metadata: metadata :param request_form: form, template_args A tuple containing the form for this location and any additional template arguments :param error_messages: The default error messages to use within the form :param disable_mandatory: Make mandatory answers optional """ if disable_mandatory: block_json = disable_mandatory_answers(block_json) if location.block_id == 'household-composition': return generate_household_composition_form(schema, block_json, request_form, metadata, location.group_instance) group_instance_id = get_group_instance_id(schema, answer_store, location) if schema.block_has_question_type(location.block_id, 'Relationship'): group = schema.get_group(location.group_id) answer_ids = [] repeat_rule = group['routing_rules'][0]['repeat'] if 'answer_ids' in repeat_rule: for answer_id in repeat_rule['answer_ids']: answer_ids.append(answer_id) if 'answer_id' in repeat_rule: answer_ids.append(repeat_rule['answer_id']) relationship_choices = build_relationship_choices( answer_ids, answer_store, location.group_instance) form = generate_relationship_form(schema, block_json, relationship_choices, request_form, location.group_instance, group_instance_id) return form data = clear_other_text_field(request_form, schema.get_questions_for_block(block_json)) return generate_form(schema, block_json, answer_store, metadata, location.group_instance, group_instance_id, formdata=data)
def get_form_for_location(schema, block_json, location, answer_store, metadata, disable_mandatory=False): # pylint: disable=too-many-locals """ Returns the form necessary for the location given a get request, plus any template arguments :param schema: schema :param block_json: The block json :param location: The location which this form is for :param answer_store: The current answer store :param metadata: metadata :param disable_mandatory: Make mandatory answers optional :return: form, template_args A tuple containing the form for this location and any additional template arguments """ if disable_mandatory: block_json = disable_mandatory_answers(block_json) if location.block_id == 'household-composition': answer_ids = schema.get_answer_ids_for_block(location.block_id) answers = answer_store.filter(answer_ids, location.group_instance) data = deserialise_composition_answers(answers) return generate_household_composition_form(schema, block_json, data, metadata, location.group_instance) if location.block_id in ['relationships', 'household-relationships']: answer_ids = schema.get_answer_ids_for_block(location.block_id) answers = answer_store.filter(answer_ids, location.group_instance) data = deserialise_relationship_answers(answers) relationship_choices = build_relationship_choices( answer_store, location.group_instance) form = generate_relationship_form(schema, block_json, relationship_choices, data, location.group_instance) return form mapped_answers = get_mapped_answers( schema, answer_store, group_instance=location.group_instance, block_id=location.block_id, ) return generate_form(schema, block_json, answer_store, metadata, location.group_instance, data=mapped_answers)
def test_form_errors_are_correctly_mapped(self): form = generate_household_composition_form(self.block_json, {}, error_messages=self.error_messages) form.validate() message = "Please enter a name or remove the person to continue" self.assertTrue(self._error_exists('household-0-first-name', message, form.map_errors()))
def test_answer_errors_are_mapped(self): form = generate_household_composition_form(self.block_json, {}, error_messages=self.error_messages) form.validate() message = "Please enter a name or remove the person to continue" self.assertIn(message, form.answer_errors('household-0-first-name'))
def get_form_for_location(block_json, location, answer_store, error_messages, disable_mandatory=False): """ Returns the form necessary for the location given a get request, plus any template arguments :param disable_mandatory: Make mandatory answers optional :param error_messages: The default error messages to use within the form :param block_json: The block json :param location: The location which this form is for :param answer_store: The current answer store :return: form, template_args A tuple containing the form for this location and any additional template arguments """ if disable_mandatory: block_json = disable_mandatory_answers(block_json) if location.block_id == 'household-composition': answers = answer_store.filter(location=location) data = deserialise_composition_answers(answers) return generate_household_composition_form(block_json, data, error_messages), None elif location.block_id in ['relationships', 'household-relationships']: answers = answer_store.filter(location=location) data = deserialise_relationship_answers(answers) choices = build_relationship_choices(answer_store, location.group_instance) form = generate_relationship_form(block_json, len(choices), data, error_messages) return form, {'relation_instances': choices} else: mapped_answers = answer_store.map( group_id=location.group_id, group_instance=location.group_instance, block_id=location.block_id, ) # Form generation expects post like data, so cast answers to strings for answer_id, mapped_answer in mapped_answers.items(): if isinstance(mapped_answer, list): for index, element in enumerate(mapped_answer): mapped_answers[answer_id][index] = str(element) else: mapped_answers[answer_id] = str(mapped_answer) mapped_answers = deserialise_dates(block_json, mapped_answers) return generate_form(block_json, mapped_answers, error_messages), None
def test_serialise_answers(self): with self.app_request_context(): form = generate_household_composition_form( self.schema, self.block_json, { 'household-0-first-name': 'Joe', 'household-0-last-name': 'Bloggs', 'household-1-first-name': 'Bob', 'household-1-last-name': 'Seymour', }, metadata=self.metadata, group_instance=0) answers = form.serialise() expected_answers = [{ 'group_instance_id': None, 'group_instance': 0, 'answer_id': 'first-name', 'answer_instance': 0, 'value': 'Joe' }, { 'group_instance_id': None, 'group_instance': 0, 'answer_id': 'middle-names', 'answer_instance': 0, 'value': '' }, { 'group_instance_id': None, 'group_instance': 0, 'answer_id': 'last-name', 'answer_instance': 0, 'value': 'Bloggs' }, { 'group_instance_id': None, 'group_instance': 0, 'answer_id': 'first-name', 'answer_instance': 1, 'value': 'Bob' }, { 'group_instance_id': None, 'group_instance': 0, 'answer_id': 'middle-names', 'answer_instance': 1, 'value': '' }, { 'group_instance_id': None, 'group_instance': 0, 'answer_id': 'last-name', 'answer_instance': 1, 'value': 'Seymour' }] for _, answer in enumerate(answers): self.assertIn(answer.__dict__, expected_answers)
def test_answer_errors_are_mapped(self): with self.app_request_context(): form = generate_household_composition_form(self.schema, self.block_json, {}, metadata=self.metadata, group_instance=0) form.validate() message = 'Please enter a name or remove the person to continue' self.assertIn(message, form.answer_errors('household-0-first-name'))
def test_get_name_form_generates_name_form(self): form = generate_household_composition_form(self.block_json, {}, error_messages=self.error_messages) self.assertEqual(len(form.household.entries), 1) first_name_field = getattr(form.household.entries[0], 'first-name') middle_names_field = getattr(form.household.entries[0], 'middle-names') last_name_field = getattr(form.household.entries[0], 'last-name') self.assertIsInstance(first_name_field.validators[0], validators.InputRequired) self.assertIsInstance(middle_names_field.validators[0], validators.Optional) self.assertIsInstance(last_name_field.validators[0], validators.Optional)
def test_get_name_form_generates_name_form_with_titles(self): block_json = { 'type': 'Question', 'id': 'household-composition', 'questions': [{ 'id': 'household-composition-question', 'titles': [{ 'value': 'First Name Default' }], 'type': 'RepeatingAnswer', 'answers': [{ 'id': 'first-name', 'mandatory': True, 'type': 'TextField' }, { 'id': 'middle-names', 'mandatory': False, 'type': 'TextField' }, { 'id': 'last-name', 'mandatory': False, 'type': 'TextField' }] }] } with self.app_request_context(): form = generate_household_composition_form(self.schema, block_json, {}, metadata=self.metadata, group_instance=0) self.assertEqual(len(form.household.entries), 1) first_name_field = getattr(form.household.entries[0], 'first-name') middle_names_field = getattr(form.household.entries[0], 'middle-names') last_name_field = getattr(form.household.entries[0], 'last-name') self.assertIsInstance(first_name_field.validators[0], ResponseRequired) self.assertIsInstance(middle_names_field.validators[0], validators.Optional) self.assertIsInstance(last_name_field.validators[0], validators.Optional)
def test_whitespace_in_first_name_invalid(self): with self.test_request_context(): form = generate_household_composition_form( self.block_json, { 'household-0-first-name': ' ', 'household-0-last-name': 'Bloggs', }, error_messages=self.error_messages) form.validate() message = "Please enter a name or remove the person to continue" self.assertIn(message, form.answer_errors('household-0-first-name'))
def test_remove_person(self): with self.app_request_context(): form = generate_household_composition_form( self.schema, self.block_json, { 'household-0-first-name': 'Joe', 'household-0-last-name': 'Bloggs', 'household-1-first-name': 'Bob', 'household-1-last-name': 'Seymour', }, metadata=self.metadata, group_instance=0) self.assertEqual(len(form.household.entries), 2) with self.assertRaises(IndexError): form.remove_person(3)
def test_form_creation_with_data(self): form = generate_household_composition_form(self.block_json, { 'household-0-first-name': 'Joe', 'household-0-last-name': 'Bloggs', 'household-1-first-name': 'Jane', 'household-1-last-name': 'Seymour', }, error_messages=self.error_messages) self.assertEqual(len(form.household.entries), 2) self.assertEqual(form.household.entries[0].data, { 'first-name': 'Joe', 'middle-names': '', 'last-name': 'Bloggs' }) self.assertEqual(form.household.entries[1].data, { 'first-name': 'Jane', 'middle-names': '', 'last-name': 'Seymour' })
def test_get_name_form_generates_name_form(self): with self.app_request_context(): form = generate_household_composition_form(self.schema, self.block_json, {}, metadata=self.metadata, group_instance=0) self.assertEqual(len(form.household.entries), 1) first_name_field = getattr(form.household.entries[0], 'first-name') middle_names_field = getattr(form.household.entries[0], 'middle-names') last_name_field = getattr(form.household.entries[0], 'last-name') self.assertIsInstance(first_name_field.validators[0], ResponseRequired) self.assertIsInstance(middle_names_field.validators[0], validators.Optional) self.assertIsInstance(last_name_field.validators[0], validators.Optional)
def test_serialise_answers(self): form = generate_household_composition_form(self.block_json, { 'household-0-first-name': 'Joe', 'household-0-last-name': 'Bloggs', 'household-1-first-name': 'Bob', 'household-1-last-name': 'Seymour', }, error_messages=self.error_messages) location = Location('who-lives-here', 0, 'household-composition') answers = form.serialise(location) expected_answers = [ { 'group_id': 'who-lives-here', 'group_instance': 0, 'block_id': 'household-composition', 'answer_id': 'first-name', 'answer_instance': 0, 'value': 'Joe' }, { 'group_id': 'who-lives-here', 'group_instance': 0, 'block_id': 'household-composition', 'answer_id': 'middle-names', 'answer_instance': 0, 'value': '' }, { 'group_id': 'who-lives-here', 'group_instance': 0, 'block_id': 'household-composition', 'answer_id': 'last-name', 'answer_instance': 0, 'value': 'Bloggs' }, { 'group_id': 'who-lives-here', 'group_instance': 0, 'block_id': 'household-composition', 'answer_id': 'first-name', 'answer_instance': 1, 'value': 'Bob' }, { 'group_id': 'who-lives-here', 'group_instance': 0, 'block_id': 'household-composition', 'answer_id': 'middle-names', 'answer_instance': 1, 'value': '' }, { 'group_id': 'who-lives-here', 'group_instance': 0, 'block_id': 'household-composition', 'answer_id': 'last-name', 'answer_instance': 1, 'value': 'Seymour' } ] for i, answer in enumerate(answers): self.assertIn(answer.__dict__, expected_answers)