def populate_library_fixture(self, library_fixture): """ Populates library fixture with XBlock Fixtures """ items = ( XBlockFixtureDesc( "problem", "Problem Choice Group 1", data=self._get_problem_choice_group_text("Problem Choice Group 1 Text", [("1", False), ('2', True)]) ), XBlockFixtureDesc( "problem", "Problem Choice Group 2", data=self._get_problem_choice_group_text("Problem Choice Group 2 Text", [("Q", True), ('W', False)]) ), XBlockFixtureDesc( "problem", "Problem Select 1", data=self._get_problem_select_text("Problem Select 1 Text", ["Option 1", "Option 2"], "Option 1") ), XBlockFixtureDesc( "problem", "Problem Select 2", data=self._get_problem_select_text("Problem Select 2 Text", ["Option 3", "Option 4"], "Option 4") ), ) library_fixture.add_children(*items)
def get_problem(self): """ Create a problem. """ xml = dedent(""" <problem> <numericalresponse answer="1"> <label>The answer is 1</label> <formulaequationinput/> <responseparam type="tolerance" default="0.01" /> </numericalresponse> </problem> """) return XBlockFixtureDesc('problem', 'TEST PROBLEM', data=xml)
def create_multiple_choice_problem(self, problem_name): """ Return the Multiple Choice Problem Descriptor, given the name of the problem. """ factory = MultipleChoiceResponseXMLFactory() xml_data = factory.build_xml( question_text='The correct answer is Choice 2', choices=[False, False, True, False], choice_names=['choice_0', 'choice_1', 'choice_2', 'choice_3']) return XBlockFixtureDesc('problem', problem_name, data=xml_data, metadata={'rerandomize': 'always'})
def get_problem(self): """ Creates a {problem_type} problem """ # Generate the problem XML using capa.tests.response_xml_factory return XBlockFixtureDesc( 'problem', self.problem_name, data=self.factory.build_xml(**self.factory_kwargs), metadata={ 'rerandomize': 'never', 'show_reset_button': True, 'max_attempts': 3 })
def populate_course_fixture(self, course_fixture): """ Populates test course with chapter, sequential, and 2 problems. """ problem_data = dedent(""" <problem markdown="Simple Problem" max_attempts="" weight=""> <p>Choose Yes.</p> <choiceresponse> <checkboxgroup> <choice correct="true">Yes</choice> </checkboxgroup> </choiceresponse> </problem> """) course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc('problem', 'Test Problem 1', data=problem_data), XBlockFixtureDesc('problem', 'Test Problem 2', data=problem_data) ) ) )
def setUp(self): super(EntranceExamTest, self).setUp() self.xqueue_grade_response = None self.courseware_page = CoursewarePage(self.browser, self.course_id) # Install a course with a hierarchy and problems course_fixture = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'], settings={ 'entrance_exam_enabled': 'true', 'entrance_exam_minimum_score_pct': '50' } ) problem = self.get_problem() course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children(problem) ) ).install() entrance_exam_subsection = None outline = course_fixture.studio_course_outline_as_json for child in outline['child_info']['children']: if child.get('display_name') == "Entrance Exam": entrance_exam_subsection = child['child_info']['children'][0] if entrance_exam_subsection: course_fixture.create_xblock(entrance_exam_subsection['id'], problem) # Auto-auth register for the course. AutoAuthPage(self.browser, username=self.USERNAME, email=self.EMAIL, course_id=self.course_id, staff=False).visit()
def setUp(self): """ Create search page and course content to search """ # create test file in which index for this test will live with open(self.TEST_INDEX_FILENAME, "w+") as index_file: json.dump({}, index_file) self.addCleanup(remove_file, self.TEST_INDEX_FILENAME) super(CoursewareSearchTest, self).setUp() self.course_home_page = CourseHomePage(self.browser, self.course_id) self.studio_course_outline = StudioCourseOutlinePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'] ) course_fix = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'] ) course_fix.add_children( XBlockFixtureDesc('chapter', 'Section 1').add_children( XBlockFixtureDesc('sequential', 'Subsection 1') ) ).add_children( XBlockFixtureDesc('chapter', 'Section 2').add_children( XBlockFixtureDesc('sequential', 'Subsection 2') ) ).install()
def create_course_fixture(self, num_chapters): """ Create course fixture Arguments: num_chapters: number of chapters to create """ self.course_fixture = CourseFixture( # pylint: disable=attribute-defined-outside-init self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name']) xblocks = [] for index in range(num_chapters): xblocks += [ XBlockFixtureDesc( 'chapter', 'TestSection{}'.format(index)).add_children( XBlockFixtureDesc( 'sequential', 'TestSubsection{}'.format(index)).add_children( XBlockFixtureDesc( 'vertical', 'TestVertical{}'.format(index)))) ] self.course_fixture.add_children(*xblocks).install()
def setUp(self): super(BaseDiscussionTestCase, self).setUp() self.discussion_id = "test_discussion_{}".format(uuid4().hex) self.course_fixture = CourseFixture(**self.course_info) self.course_fixture.add_children( XBlockFixtureDesc("chapter", "Test Section").add_children( XBlockFixtureDesc("sequential", "Test Subsection").add_children( XBlockFixtureDesc("vertical", "Test Unit").add_children( XBlockFixtureDesc( "discussion", "Test Discussion", metadata={"discussion_id": self.discussion_id} ) ) ) ) ) self.course_fixture.add_advanced_settings( {'discussion_topics': {'value': {'General': {'id': 'course'}}}} ) self.course_fixture.install() self.enable_forums()
def test_group_configuration_non_empty_usage(self): """ Scenario: When group configuration is used, ensure that the links to units using a group configuration work correctly. Given I have a course without group configurations And I create new group configuration with 2 default groups And I create a unit and assign the newly created group configuration And open the Group Configuration page Then I see a link to the newly created unit When I click on the unit link Then I see correct unit page """ # Create a new group configurations self.course_fixture._update_xblock(self.course_fixture._course_location, { "metadata": { u"user_partitions": [ create_user_partition_json( 0, "Name", "Description.", [Group("0", "Group A"), Group("1", "Group B")] ), ], }, }) # Assign newly created group configuration to unit vertical = self.course_fixture.get_nested_xblocks(category="vertical")[0] self.course_fixture.create_xblock( vertical.locator, XBlockFixtureDesc('split_test', 'Test Content Experiment', metadata={'user_partition_id': 0}) ) unit = CourseOutlineUnit(self.browser, vertical.locator) # Go to the Group Configuration Page and click unit anchor self.page.visit() config = self.page.experiment_group_configurations[0] config.toggle() usage = config.usages[0] config.click_unit_anchor() unit = ContainerPage(self.browser, vertical.locator) # Waiting for the page load and verify that we've landed on the unit page EmptyPromise( lambda: unit.is_browser_on_page(), "loaded page {!r}".format(unit), timeout=30 ).fulfill() self.assertIn(unit.name, usage)
def get_problem(self): """ creating the formula response problem, with reset button enabled. """ xml = dedent(""" <problem> <formularesponse type="ci" samples="R_1,R_2,R_3@1,2,3:3,4,5#10" answer="R_1*R_2/R_3"> <p>You can use this template as a guide to the OLX markup to use for math expression problems. Edit this component to replace the example with your own assessment.</p> <label>Add the question text, or prompt, here. This text is required. Example: Write an expression for the product of R_1, R_2, and the inverse of R_3.</label> <description>You can add an optional tip or note related to the prompt like this. Example: To test this example, the correct answer is R_1*R_2/R_3</description> <responseparam type="tolerance" default="0.00001"/> <formulaequationinput size="40"/> </formularesponse> </problem> """) return XBlockFixtureDesc('problem', 'TEST PROBLEM', data=xml, metadata={'show_reset_button': True})
def get_problem(self): """MathExpressionInput problem XML.""" xml = dedent(r""" <problem> <script type="loncapa/python"> derivative = "n*x^(n-1)" </script> <formularesponse type="ci" samples="x,n@1,2:3,4#10" answer="$derivative"> <label>Let \( x\) be a variable, and let \( n\) be an arbitrary constant. What is the derivative of \( x^n\)?</label> <description>Enter the equation</description> <responseparam type="tolerance" default="0.00001"/> <formulaequationinput size="40"/> </formularesponse> </problem>""") return XBlockFixtureDesc('problem', 'MATHEXPRESSIONINPUT PROBLEM', data=xml)
def get_problem(self): """ Create a problem with partial credit. """ xml = dedent(""" <problem> <p>The answer is 1. Partial credit for -1.</p> <numericalresponse answer="1" partial_credit="list"> <label>How many miles away from Earth is the sun? Use scientific notation to answer.</label> <formulaequationinput/> <responseparam type="tolerance" default="0.01" /> <responseparam partial_answers="-1" /> </numericalresponse> </problem> """) return XBlockFixtureDesc('problem', 'PARTIAL CREDIT TEST PROBLEM', data=xml)
def test_no_content_message(self): """ Scenario: Given I have a library, a course and library content xblock in a course When I go to studio unit page for library content block And I set Problem Type selector so that no libraries have matching content Then I can see that "No matching content" warning is shown When I set Problem Type selector so that there is matching content Then I can see that warning messages are not shown """ # Add a single "Dropdown" type problem to the library (which otherwise has only HTML blocks): self.library_fixture.create_xblock(self.library_fixture.library_location, XBlockFixtureDesc( "problem", "Dropdown", data=textwrap.dedent(""" <problem> <p>Dropdown</p> <optionresponse><optioninput label="Dropdown" options="('1', '2')" correct="'2'"></optioninput></optionresponse> </problem> """) )) expected_text = 'There are no matching problem types in the specified libraries. Select another problem type' library_container = self._get_library_xblock_wrapper(self.unit_page.xblocks[1]) # precondition check - assert library has children matching filter criteria self.assertFalse(library_container.has_validation_error) self.assertFalse(library_container.has_validation_warning) library_container.edit() edit_modal = StudioLibraryContentEditor(self.browser, library_container.locator) self.assertEqual(edit_modal.capa_type, "Any Type") # precondition check edit_modal.capa_type = "Custom Evaluated Script" library_container.save_settings() self.assertTrue(library_container.has_validation_warning) self.assertIn(expected_text, library_container.validation_warning_text) library_container.edit() edit_modal = StudioLibraryContentEditor(self.browser, library_container.locator) self.assertEqual(edit_modal.capa_type, "Custom Evaluated Script") # precondition check edit_modal.capa_type = "Dropdown" library_container.save_settings() # Library should contain single Dropdown problem, so now there should be no errors again self.assertFalse(library_container.has_validation_error) self.assertFalse(library_container.has_validation_warning)
def get_problem(self): """ Create a multiple choice problem """ xml = dedent(""" <problem> <multiplechoiceresponse> <label>What is height of eiffel tower without the antenna?.</label> <choicegroup type="MultipleChoice"> <choice correct="false">324 meters<choicehint>Antenna is 24 meters high</choicehint></choice> <choice correct="true">300 meters</choice> <choice correct="false">224 meters</choice> <choice correct="false">400 meters</choice> </choicegroup> </multiplechoiceresponse> </problem> """) return XBlockFixtureDesc('problem', 'HEIGHT OF EIFFEL TOWER', data=xml)
def get_problem(self): """ Problem structure """ xml = dedent(""" <problem> <label>Which of the following countries has the largest population?</label> <multiplechoiceresponse> <choicegroup type="MultipleChoice"> <choice correct="false">Brazil <choicehint>timely feedback -- explain why an almost correct answer is wrong</choicehint></choice> <choice correct="false">Germany</choice> <choice correct="true">Indonesia</choice> <choice correct="false">Russia</choice> </choicegroup> </multiplechoiceresponse> </problem> """) return XBlockFixtureDesc('problem', 'TEST PROBLEM', data=xml)
def setUp(self): super(AnnotatableProblemTest, self).setUp() self.courseware_page = CoursewarePage(self.browser, self.course_id) # Install a course with two annotations and two annotations problems. course_fix = CourseFixture(self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name']) self.annotation_count = 2 course_fix.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection'). add_children( XBlockFixtureDesc( 'vertical', 'Test Annotation Vertical').add_children( XBlockFixtureDesc( 'annotatable', 'Test Annotation Module', data=self.DATA_TEMPLATE.format("\n".join( self.ANNOTATION_TEMPLATE.format(i) for i in range(self.annotation_count)))), XBlockFixtureDesc( 'problem', 'Test Annotation Problem 0', data=self.PROBLEM_TEMPLATE.format( number=0, options="\n".join( self.OPTION_TEMPLATE.format( number=k, correctness=_correctness(k, 0)) for k in range(self.annotation_count)))), XBlockFixtureDesc( 'problem', 'Test Annotation Problem 1', data=self.PROBLEM_TEMPLATE.format( number=1, options="\n".join( self.OPTION_TEMPLATE.format( number=k, correctness=_correctness(k, 1)) for k in range(self.annotation_count) ))))))).install() # Auto-auth register for the course. AutoAuthPage(self.browser, username=self.USERNAME, email=self.EMAIL, course_id=self.course_id, staff=False).visit()
def get_problem(self): """ Problem with extended hint features. """ xml = dedent(""" <problem> <p>question text</p> <stringresponse answer="A"> <stringequalhint answer="C"><a href="#">aa bb</a> cc</stringequalhint> <textline size="20"/> </stringresponse> <demandhint> <hint>aa <a href="#">bb</a> cc</hint> <hint><a href="#">dd ee</a> ff</hint> </demandhint> </problem> """) return XBlockFixtureDesc('problem', 'PROBLEM HTML HINT TEST', data=xml)
def get_problem(self): """ Create a problem with question and description. """ xml = dedent(u""" <problem> <choiceresponse> <label>Eggplant is a _____?</label> <description>{}</description> <description>{}</description> <checkboxgroup> <choice correct="true">vegetable</choice> <choice correct="false">fruit</choice> </checkboxgroup> </choiceresponse> </problem> """.format(*self.descriptions)) return XBlockFixtureDesc('problem', 'Label with Description', data=xml)
def get_problem(self): """ Problem with extended hint features. """ xml = dedent(""" <problem> <p>question text</p> <stringresponse answer="A"> <stringequalhint answer="B">hint</stringequalhint> <textline size="20"/> </stringresponse> <demandhint> <hint>demand-hint1</hint> <hint>demand-hint2</hint> </demandhint> </problem> """) return XBlockFixtureDesc('problem', 'TITLE', data=xml)
def populate_course_fixture(self, course_fixture): """ Populate the children of the test course fixture. """ self.group_a_problem = 'GROUP A CONTENT' self.group_b_problem = 'GROUP B CONTENT' self.group_verified_problem = 'GROUP VERIFIED CONTENT' self.group_audit_problem = 'GROUP AUDIT CONTENT' self.group_a_and_b_problem = 'GROUP A AND B CONTENT' self.visible_to_all_problem = 'VISIBLE TO ALL CONTENT' course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc( 'sequential', 'Test Subsection').add_children( XBlockFixtureDesc( 'vertical', 'Test Unit').add_children( XBlockFixtureDesc('problem', self.group_a_problem, data='<problem></problem>'), XBlockFixtureDesc('problem', self.group_b_problem, data='<problem></problem>'), XBlockFixtureDesc('problem', self.group_verified_problem, data='<problem></problem>'), XBlockFixtureDesc('problem', self.group_audit_problem, data='<problem></problem>'), XBlockFixtureDesc('problem', self.group_a_and_b_problem, data='<problem></problem>'), XBlockFixtureDesc( 'problem', self.visible_to_all_problem, data='<problem></problem>')))))
def test_cannot_delete_used_content_group(self): """ Scenario: Ensure that the user cannot delete used content group. Given I have a course with 1 Content Group And I go to the Group Configuration page When I try to delete the Content Group with name "New Content Group" Then I see the delete button is disabled. """ self.course_fixture._update_xblock( self.course_fixture._course_location, { "metadata": { u"user_partitions": [ create_user_partition_json(0, 'Configuration alpha,', 'Content Group Partition', [Group("0", 'alpha')], scheme="cohort") ], }, }) problem_data = dedent(""" <problem markdown="Simple Problem" max_attempts="" weight=""> <p>Choose Yes.</p> <choiceresponse> <checkboxgroup> <choice correct="true">Yes</choice> </checkboxgroup> </choiceresponse> </problem> """) vertical = self.course_fixture.get_nested_xblocks( category="vertical")[0] self.course_fixture.create_xblock( vertical.locator, XBlockFixtureDesc('problem', "VISIBLE TO ALPHA", data=problem_data, metadata={"group_access": { 0: [0] }}), ) self.group_configurations_page.visit() config = self.group_configurations_page.content_groups[0] self.assertTrue(config.delete_button_is_disabled)
def get_problem(self): """ Create a problem with a <clarification> """ xml = dedent(""" <problem markdown="null"> <text> <p> Given the data in Table 7 <clarification>Table 7: "Example PV Installation Costs", Page 171 of Roberts textbook</clarification>, compute the ROI <clarification>Return on Investment <strong>(per year)</strong></clarification> over 20 years. </p> <numericalresponse answer="6.5"> <textline label="Enter the annual ROI" trailing_text="%" /> </numericalresponse> </text> </problem> """) return XBlockFixtureDesc('problem', 'TOOLTIP TEST PROBLEM', data=xml)
def get_problem(self): """ Create a problem with a <MathJax> in body and hint """ xml = dedent(r""" <problem> <p>Check mathjax has rendered [mathjax]E=mc^2[/mathjax]</p> <multiplechoiceresponse> <choicegroup label="Answer this?" type="MultipleChoice"> <choice correct="true">Choice1 <choicehint>Correct choice message</choicehint></choice> <choice correct="false">Choice2<choicehint>Wrong choice message</choicehint></choice> </choicegroup> </multiplechoiceresponse> <demandhint> <hint>mathjax should work1 \(E=mc^2\) </hint> <hint>mathjax should work2 [mathjax]E=mc^2[/mathjax]</hint> </demandhint> </problem> """) return XBlockFixtureDesc('problem', 'MATHJAX TEST PROBLEM', data=xml)
def get_problem(self): """ Problem structure. """ xml = dedent(""" <problem> <optionresponse> <p>You can use this template as a guide to the simple editor markdown and OLX markup to use for dropdown problems. Edit this component to replace this template with your own assessment.</p> <label>Which of the following is a fruit</label> <description>Choose wisely</description> <optioninput> <option correct="False">radish</option> <option correct="True">appple</option> <option correct="False">carrot</option> </optioninput> </optionresponse> </problem> """) return XBlockFixtureDesc('problem', 'Problem A11Y TEST', data=xml)
def get_problem(self): """ TextInput problem XML. """ xml = dedent(""" <problem> <stringresponse answer="fight" type="ci"> <label>who wishes to _____ must first count the cost.</label> <description>Appear weak when you are strong, and strong when you are weak.</description> <description>In the midst of chaos, there is also opportunity.</description> <textline size="40"/> </stringresponse> <stringresponse answer="force" type="ci"> <label>A leader leads by example not by _____.</label> <description>The supreme art of war is to subdue the enemy without fighting.</description> <description>Great results, can be achieved with small forces.</description> <textline size="40"/> </stringresponse> </problem>""") return XBlockFixtureDesc('problem', 'TEXTINPUT PROBLEM', data=xml)
def test_cannot_delete_used_group_configuration(self): """ Scenario: Ensure that the user cannot delete unused group configuration. Given I have a course with group configuration that is used in the Content Experiment When I go to the Group Configuration page Then I do not see delete button and I see a note about that When I edit the Group Configuration Then I do not see delete button and I see the note about that """ # Create a new group configurations self.course_fixture._update_xblock( self.course_fixture._course_location, { "metadata": { u"user_partitions": [ create_user_partition_json( 0, "Name", "Description.", [Group("0", "Group A"), Group("1", "Group B")]) ], }, }) vertical = self.course_fixture.get_nested_xblocks( category="vertical")[0] self.course_fixture.create_xblock( vertical.locator, XBlockFixtureDesc('split_test', 'Test Content Experiment', metadata={'user_partition_id': 0})) # Go to the Group Configuration Page and click unit anchor self.page.visit() config = self.page.experiment_group_configurations[0] self.assertTrue(config.delete_button_is_disabled) self.assertIn('Cannot delete when in use by an experiment', config.delete_note) config.edit() self.assertTrue(config.delete_button_is_disabled) self.assertIn('Cannot delete when in use by an experiment', config.delete_note)
def setup_fixtures(self): course_fix = CourseFixture( self.course_info['org'], self.course_info['number'], self.course_info['run'], self.course_info['display_name'] ) course_fix.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc('vertical', 'Test Unit').add_children( XBlockFixtureDesc('acid_parent', 'Acid Parent Block').add_children( XBlockFixtureDesc('acid', 'First Acid Child', metadata={'name': 'first'}), XBlockFixtureDesc('acid', 'Second Acid Child', metadata={'name': 'second'}), XBlockFixtureDesc('html', 'Html Child', data="<html>Contents</html>"), ) ) ) ) ).install()
def populate_course_fixture(self, course_fixture): """ Populate the children of the test course fixture. """ self.group_a_html = 'GROUPACONTENT' self.group_b_html = 'GROUPBCONTENT' self.group_a_and_b_html = 'GROUPAANDBCONTENT' self.visible_to_all_html = 'VISIBLETOALLCONTENT' course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc('vertical', 'Test Unit').add_children( XBlockFixtureDesc('html', self.group_a_html, data='<html>GROUPACONTENT</html>'), XBlockFixtureDesc('html', self.group_b_html, data='<html>GROUPBCONTENT</html>'), XBlockFixtureDesc('html', self.group_a_and_b_html, data='<html>GROUPAANDBCONTENT</html>'), XBlockFixtureDesc('html', self.visible_to_all_html, data='<html>VISIBLETOALLCONTENT</html>') ) ) ) )
def populate_course_fixture(self, course_fixture): """ Populates test course with chapter, sequential, and 3 problems. One problem is visible to all, one problem is visible only to Group "alpha", and one problem is visible only to Group "beta". """ problem_data = dedent(""" <problem markdown="Simple Problem" max_attempts="" weight=""> <p>Choose Yes.</p> <choiceresponse> <checkboxgroup> <choice correct="true">Yes</choice> </checkboxgroup> </choiceresponse> </problem> """) self.alpha_text = "VISIBLE TO ALPHA" self.beta_text = "VISIBLE TO BETA" self.everyone_text = "VISIBLE TO EVERYONE" course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc( 'sequential', 'Test Subsection').add_children( XBlockFixtureDesc( 'vertical', 'Test Unit').add_children( XBlockFixtureDesc( 'problem', self.alpha_text, data=problem_data, metadata={"group_access": { 0: [0] }}), XBlockFixtureDesc( 'problem', self.beta_text, data=problem_data, metadata={"group_access": { 0: [1] }}), XBlockFixtureDesc('problem', self.everyone_text, data=problem_data)))))