import textwrap from lettuce import world, steps from nose.tools import assert_in, assert_equals, assert_true from common import i_am_registered_for_the_course, visit_scenario_item DATA_TEMPLATE = textwrap.dedent("""\ Instruction text

{}

""") ANNOTATION_TEMPLATE = textwrap.dedent("""\ Before {0}. Region Contents {0} After {0}. """) PROBLEM_TEMPLATE = textwrap.dedent("""\ Question {number} Region Contents {number} What number is this region? Type your response below: What number is this region? {options} This problem is checking region {number} """) OPTION_TEMPLATE = """""" def _correctness(choice, target): if choice == target: return "correct" elif abs(choice - target) == 1: return "partially-correct" else: return "incorrect" @steps class AnnotatableSteps(object): def __init__(self): self.annotations_count = None self.active_problem = None def define_component(self, step, count): r"""that a course has an annotatable component with (?P\d+) annotations$""" count = int(count) coursenum = 'test_course' i_am_registered_for_the_course(step, coursenum) world.scenario_dict['ANNOTATION_VERTICAL'] = world.ItemFactory( parent_location=world.scenario_dict['SECTION'].location, category='vertical', display_name="Test Annotation Vertical" ) world.scenario_dict['ANNOTATABLE'] = world.ItemFactory( parent_location=world.scenario_dict['ANNOTATION_VERTICAL'].location, category='annotatable', display_name="Test Annotation Module", data=DATA_TEMPLATE.format("\n".join(ANNOTATION_TEMPLATE.format(i) for i in xrange(count))) ) self.annotations_count = count def view_component(self, step): r"""I view the annotatable component$""" visit_scenario_item('ANNOTATABLE') def check_rendered(self, step): r"""the annotatable component has rendered$""" world.wait_for_js_variable_truthy('$(".xblock-student_view[data-type=Annotatable]").data("initialized")') annotatable_text = world.css_find('.xblock-student_view[data-type=Annotatable]').first.text assert_in("Instruction text", annotatable_text) for i in xrange(self.annotations_count): assert_in("Region Contents {}".format(i), annotatable_text) def count_passages(self, step, count): r"""the annotatable component has (?P\d+) highlighted passages$""" count = int(count) assert_equals(len(world.css_find('.annotatable-span')), count) assert_equals(len(world.css_find('.annotatable-span.highlight')), count) assert_equals(len(world.css_find('.annotatable-span.highlight-yellow')), count) def add_problems(self, step, count): r"""the course has (?P\d+) annotatation problems$""" count = int(count) for i in xrange(count): world.scenario_dict.setdefault('PROBLEMS', []).append( world.ItemFactory( parent_location=world.scenario_dict['ANNOTATION_VERTICAL'].location, category='problem', display_name="Test Annotation Problem {}".format(i), data=PROBLEM_TEMPLATE.format( number=i, options="\n".join( OPTION_TEMPLATE.format( number=k, correctness=_correctness(k, i) ) for k in xrange(count) ) ) ) ) def click_reply(self, step, problem): r"""I click "Reply to annotation" on passage (?P\d+)$""" problem = int(problem) annotation_span_selector = '.annotatable-span[data-problem-id="{}"]'.format(problem) world.css_find(annotation_span_selector).first.mouse_over() annotation_reply_selector = '.annotatable-reply[data-problem-id="{}"]'.format(problem) assert_equals(len(world.css_find(annotation_reply_selector)), 1) world.css_click(annotation_reply_selector) self.active_problem = problem def active_problem_selector(self, subselector): return 'div[data-problem-id="{}"] {}'.format( world.scenario_dict['PROBLEMS'][self.active_problem].location.url(), subselector, ) def check_scroll_to_problem(self, step): r"""I am scrolled to that annotation problem$""" annotation_input_selector = self.active_problem_selector('.annotation-input') assert_true(world.css_visible(annotation_input_selector)) def answer_problem(self, step): r"""I answer that annotation problem$""" world.css_fill(self.active_problem_selector('.comment'), 'Test Response') world.css_click(self.active_problem_selector('.tag[data-id="{}"]'.format(self.active_problem))) world.css_click(self.active_problem_selector('.check')) def check_feedback(self, step): r"""I receive feedback on that annotation problem$""" world.wait_for_visible(self.active_problem_selector('.tag-status.correct')) assert_equals(len(world.css_find(self.active_problem_selector('.tag-status.correct'))), 1) assert_equals(len(world.css_find(self.active_problem_selector('.show'))), 1) def click_return_to(self, step): r"""I click "Return to annotation" on that problem$""" world.css_click(self.active_problem_selector('.annotation-return')) def check_scroll_to_annotatable(self, step): r"""I am scrolled to the annotatable component$""" assert_true(world.css_visible('.annotation-header')) # This line is required by @steps in order to actually bind the step # regexes AnnotatableSteps()