def test_previous_with_conditional_path(self): survey = load_schema_file("0_star_wars.json") expected_path = [ "f22b1ba4-d15f-48b8-a1f3-db62b6f34cc0", "923ccc84-9d47-4a02-8ebc-1e9d14fcf10b", "26f2c4b3-28ac-4072-9f18-a6a6c6f660db", "cd3b74d1-b687-4051-9634-a8f9ce10a27d", "an3b74d1-b687-4051-9634-a8f9ce10ard", "846f8514-fed2-4bd7-8fb2-4b5fcb1622b1" ] answers = { "ca3ce3a3-ae44-4e30-8f85-5b6a7a2fb23c": "Dark Side", "pel989b8-5185-4ba6-b73f-c126e3a06ba7": "Can I be a pain and have a goodies ship" } current_block_id = expected_path[3] expected_previous_block_id = expected_path[2] navigator = Navigator(survey) actual_previous_block_id = navigator.get_previous_location(answers, current_block_id) self.assertEqual(actual_previous_block_id, expected_previous_block_id) current_block_id = expected_path[2] expected_previous_block_id = expected_path[1] actual_previous_block_id = navigator.get_previous_location(answers, current_block_id) self.assertEqual(actual_previous_block_id, expected_previous_block_id)
def test_first_block(self): survey = load_schema_file("1_0102.json") first_block_id = "5bce8d8f-0af8-4d35-b77d-744e6179b406" navigator = Navigator(survey) self.assertEqual(navigator.get_first_block_id(), first_block_id)
def test_next_location_empty_routing_rules(self): survey = load_schema_file("test_checkbox.json") navigator = Navigator(survey) # Force some empty routing rules navigator.blocks[0]['routing_rules'] = [] expected_path = [ 'introduction', 'f22b1ba4-d15f-48b8-a1f3-db62b6f34cc0', 'f22b1ba4-d15f-48b8-a1f3-db62b6f34cc1', 'summary' ] answers = { "ca3ce3a3-ae44-4e30-8f85-5b6a7a2fb23c": "Cheese", "ca3ce3a3-ae44-4e30-8f85-5b6a7a2fb23": "deep pan", } current_location_id = expected_path[1] expected_next_location_id = expected_path[2] next_location_id = navigator.get_next_location(answers, current_location_id) self.assertEqual(next_location_id, expected_next_location_id)
def test_next_with_conditional_path(self): survey = load_schema_file("0_star_wars.json") expected_path = [ "f22b1ba4-d15f-48b8-a1f3-db62b6f34cc0", "96682325-47ab-41e4-a56e-8315a19ffe2a", "cd3b74d1-b687-4051-9634-a8f9ce10a27d", "an3b74d1-b687-4051-9634-a8f9ce10ard", "846f8514-fed2-4bd7-8fb2-4b5fcb1622b1" ] answers = { "ca3ce3a3-ae44-4e30-8f85-5b6a7a2fb23c": "Light Side", "2e0989b8-5185-4ba6-b73f-c126e3a06ba7": "No" } current_block_id = expected_path[1] expected_next_block_id = expected_path[2] navigator = Navigator(survey) actual_next_block_id = navigator.get_next_location(answers, current_block_id) self.assertEqual(actual_next_block_id, expected_next_block_id) current_block_id = expected_path[2] expected_next_block_id = expected_path[3] actual_next_block_id = navigator.get_next_location(answers, current_block_id) self.assertEqual(actual_next_block_id, expected_next_block_id)
def test_next_block(self): survey = load_schema_file("1_0102.json") current_block_id = "7418732e-12fb-4270-8307-5682ac63bfae" next_block_id = "02ed26ad-4cfc-4e29-a946-630476228b2c" navigator = Navigator(survey) self.assertEqual(navigator.get_next_location(current_location_id=current_block_id), next_block_id)
def test_get_previous_location(self): survey = load_schema_file("0_star_wars.json") navigator = Navigator(survey) next_location = navigator.get_previous_location(current_location_id='f22b1ba4-d15f-48b8-a1f3-db62b6f34cc0') self.assertEqual('introduction', next_location)
def test_interstitial_post_blocks(self): survey = load_schema_file("0_star_wars.json") navigator = Navigator(survey) answers = { "ca3ce3a3-ae44-4e30-8f85-5b6a7a2fb23c": "Light Side" } self.assertFalse('summary' in navigator.get_location_path(answers))
def test_routing_basic_path(self): survey = load_schema_file("1_0112.json") expected_path = [ "980b148e-0856-4e50-9afe-67a4fa6ae13b", "6c8a2f39-e0d8-406f-b463-2151225abea2", "0c7c8876-6a63-4251-ac29-b821b3e9b1bc", "a42b5752-1896-4f52-9d58-320085be92a7", "0b29d3f7-5905-43d8-9921-5b353db68104", "7e2d49eb-ffc7-4a61-a45d-eba336d1d0e6", ] navigator = Navigator(survey) routing_path = navigator.get_routing_path() self.assertEqual(routing_path, expected_path)
def test_next_location_goto_summary(self): survey = load_schema_file("0_star_wars.json") navigator = Navigator(survey) expected_path = [ 'introduction', 'f22b1ba4-d15f-48b8-a1f3-db62b6f34cc0', 'summary' ] answers = { "ca3ce3a3-ae44-4e30-8f85-5b6a7a2fb23c": "I prefer Star Trek" } current_location_id = expected_path[1] expected_next_location_id = expected_path[2] next_location_id = navigator.get_next_location(answers, current_location_id) self.assertEqual(next_location_id, expected_next_location_id)
def test_routing_conditional_path(self): survey = load_schema_file("0_star_wars.json") expected_path = [ "f22b1ba4-d15f-48b8-a1f3-db62b6f34cc0", "96682325-47ab-41e4-a56e-8315a19ffe2a", "cd3b74d1-b687-4051-9634-a8f9ce10a27d", "an3b74d1-b687-4051-9634-a8f9ce10ard", "846f8514-fed2-4bd7-8fb2-4b5fcb1622b1" ] answers = { "ca3ce3a3-ae44-4e30-8f85-5b6a7a2fb23c": "Light Side", "2e0989b8-5185-4ba6-b73f-c126e3a06ba7": "No" } navigator = Navigator(survey) routing_path = navigator.get_routing_path(answers) self.assertEqual(routing_path, expected_path)
class TestConfirmationPage(unittest.TestCase): def setUp(self): survey = load_schema_file("0_rogue_one.json") self.navigator = Navigator(survey) def test_get_next_location_confirmation(self): current_location_id = "5e633f04-073a-44c0-a9da-a7cc2116b937" answers = {"ca3ce3a3-ae44-4e30-8f85-5b6a7a2fb23c": "Orson Krennic"} next_location = self.navigator.get_next_location(answers, current_location_id) self.assertEqual("summary", next_location)
def test_get_next_location_summary(self): survey = load_schema_file("0_star_wars.json") navigator = Navigator(survey) answers = { "ca3ce3a3-ae44-4e30-8f85-5b6a7a2fb23c": "Light Side", "2e0989b8-5185-4ba6-b73f-c126e3a06ba7": "No" } current_location_id = 'an3b74d1-b687-4051-9634-a8f9ce10ard' next_location_id = navigator.get_next_location(answers, current_location_id) expected_next_location_id = '846f8514-fed2-4bd7-8fb2-4b5fcb1622b1' self.assertEqual(expected_next_location_id, next_location_id) current_location_id = '846f8514-fed2-4bd7-8fb2-4b5fcb1622b1' next_location_id = navigator.get_next_location(answers, current_location_id) expected_next_location_id = 'summary' self.assertEqual(expected_next_location_id, next_location_id)
def __init__(self, schema, json=None): self._json = json self._schema = schema self.state = None self.navigator = Navigator(self._json)
class QuestionnaireManager(object): ''' This class represents a user journey through a survey. It models the request/response process of the web application ''' def __init__(self, schema, json=None): self._json = json self._schema = schema self.state = None self.navigator = Navigator(self._json) def validate(self, location, post_data): answers = get_answers(current_user) if location in self.navigator.get_location_path(answers): self.build_state(location, post_data) if self.state: self._conditional_display(self.state) is_valid = self.state.schema_item.validate(self.state) # Todo, this doesn't feel right, validation is casting the user values to their type. return is_valid else: # Item has node, but is not in schema: must be introduction, thank you or summary return True else: # Not a validation location, so can't be valid return False def validate_all_answers(self): answers = get_answers(current_user) for location in self.navigator.get_location_path(answers): is_valid = self.validate(location, get_answers(current_user)) if not is_valid: logger.debug("Failed validation with current location %s", location) return False, location return True, None def process_incoming_answers(self, location, post_data): logger.debug("Processing post data for %s", location) is_valid = self.validate(location, post_data) # run the validator to update the validation_store if is_valid: # Store answers in QuestionnaireStore questionnaire_store = get_questionnaire_store(current_user.user_id, current_user.user_ik) for answer in self.get_state_answers(location): questionnaire_store.answers[answer.id] = answer.value if location not in questionnaire_store.completed_blocks: questionnaire_store.completed_blocks.append(location) questionnaire_store.save() return is_valid def get_rendering_context(self, location, is_valid=True): if is_valid: if location == 'summary': return self.get_summary_rendering_context() else: # apply page answers? self.build_state(location, get_answers(current_user)) if self.state: self._plumbing_preprocessing() self._conditional_display(self.state) # look up the preprocessor and then build the view data return build_questionnaire_model(self._json, self.state) def get_summary_rendering_context(self): schema_template_context = get_schema_template_context(self, self._schema) rendered_questionnaire_schema_json = render_template_string(json.dumps(self._json), **schema_template_context) # look up the preprocessor and then build the view data return build_summary_model(json.loads(rendered_questionnaire_schema_json)) def build_state(self, item_id, answers): # Build the state from the answers self.state = None if self._schema.item_exists(item_id): schema_item = self._schema.get_item_by_id(item_id) self.state = schema_item.construct_state() self.state.update_state(answers) def get_state_answers(self, item_id): # get the answers from the state if self._schema.item_exists(item_id): return self.state.get_answers() return [] def _plumbing_preprocessing(self): # Run the current state through the plumbing preprocessor plumbing_template_preprocessor = PlumbingPreprocessor() plumbing_template_preprocessor.plumb_current_state(self, self.state, self._schema) def _conditional_display(self, item): # Process any conditional display rules if item.schema_item: item.skipped = False if hasattr(item.schema_item, 'skip_condition') and item.schema_item.skip_condition: rule = item.schema_item.skip_condition.__dict__ rule['when'] = rule['when'].__dict__ answer = get_answers(current_user).get(rule['when']['id']) item.skipped = evaluate_rule(rule, answer) for child in item.children: self._conditional_display(child) def get_schema_item_by_id(self, item_id): return self._schema.get_item_by_id(item_id) def get_schema(self): return self._schema
def setUp(self): survey = load_schema_file("0_rogue_one.json") self.navigator = Navigator(survey)