class DiscussionComponentTest(ContainerBase): """ Feature: CMS.Component Adding As a course author, I want to be able to add and edit Discussion component """ def setUp(self, is_staff=True): """ Create a course with a section, subsection, and unit to which to add the component. """ super(DiscussionComponentTest, self).setUp(is_staff=is_staff) self.component = 'discussion' self.unit = self.go_to_unit_page() self.container_page = ContainerPage(self.browser, None) # Add Discussion component add_component(self.container_page, 'discussion', self.component) self.component = self.unit.xblocks[1] self.container_page.edit() self.discussion_editor = DiscussionComponentEditor(self.browser, self.component.locator) def populate_course_fixture(self, course_fixture): """ Adds a course fixture """ course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc('vertical', 'Test Unit') ) ) ) def test_view_discussion_component_metadata(self): """ Scenario: Staff user can view discussion component metadata Given I am in Studio and I have added a Discussion component When I edit Discussion component Then I see three settings and their expected values """ field_values = self.discussion_editor.edit_discussion_field_values self.assertEqual( field_values, ['Discussion', 'Week 1', 'Topic-Level Student-Visible Label'] ) def test_edit_discussion_component(self): """ Scenario: Staff user can modify display name Given I am in Studio and I have added a Discussion component When I open Discussion component's edit dialogue Then I can modify the display name And My display name change is persisted on save """ field_name = 'Display Name' new_name = 'Test Name' self.discussion_editor.set_field_val(field_name, new_name) self.discussion_editor.save() component_name = self.unit.xblock_titles[0] self.assertEqual(component_name, new_name)
def test_use_group_configuration(self): """ Scenario: Ensure that the group configuration can be used by split_module correctly Given I have a course without group configurations When I create new group configuration And I set new name and add a new group, save the group configuration And I go to the unit page in Studio And I add new advanced module "Content Experiment" When I assign created group configuration to the module Then I see the module has correct groups """ self.page.visit() # Create new group configuration self.page.create_experiment_group_configuration() config = self.page.experiment_group_configurations[0] config.name = "New Group Configuration Name" # Add new group config.add_group() config.groups[2].name = "New group" # Save the configuration config.save() split_test = self._add_split_test_to_vertical(number=0) container = ContainerPage(self.browser, split_test.locator) container.visit() container.edit() component_editor = ComponentEditorView(self.browser, container.locator) component_editor.set_select_value_and_save('Group Configuration', 'New Group Configuration Name') self.verify_groups(container, ['Group A', 'Group B', 'New group'], [])
class DiscussionComponentTest(ContainerBase): """ Feature: CMS.Component Adding As a course author, I want to be able to add and edit Discussion component """ def setUp(self, is_staff=True): """ Create a course with a section, subsection, and unit to which to add the component. """ super(DiscussionComponentTest, self).setUp(is_staff=is_staff) self.component = 'discussion' self.unit = self.go_to_unit_page() self.container_page = ContainerPage(self.browser, None) # Add Discussion component add_component(self.container_page, 'discussion', self.component) self.component = self.unit.xblocks[1] self.container_page.edit() self.discussion_editor = DiscussionComponentEditor( self.browser, self.component.locator) def populate_course_fixture(self, course_fixture): """ Adds a course fixture """ course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc( 'vertical', 'Test Unit')))) def test_view_discussion_component_metadata(self): """ Scenario: Staff user can view discussion component metadata Given I am in Studio and I have added a Discussion component When I edit Discussion component Then I see three settings and their expected values """ field_values = self.discussion_editor.edit_discussion_field_values self.assertEqual( field_values, ['Discussion', 'Week 1', 'Topic-Level Student-Visible Label']) def test_edit_discussion_component(self): """ Scenario: Staff user can modify display name Given I am in Studio and I have added a Discussion component When I open Discussion component's edit dialogue Then I can modify the display name And My display name change is persisted on save """ field_name = 'Display Name' new_name = 'Test Name' self.discussion_editor.set_field_val(field_name, new_name) self.discussion_editor.save() component_name = self.unit.xblock_titles[0] self.assertEqual(component_name, new_name)
def test_easy_access_from_experiment(self): """ Scenario: When a Content Experiment uses a Group Configuration, ensure that the link to that Group Configuration works correctly. Given I have a course with two Group Configurations And Content Experiment is assigned to one Group Configuration Then I see a link to Group Configuration When I click on the Group Configuration link Then I see the Group Configurations page And I see that appropriate Group Configuration is expanded. """ # 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")]), create_user_partition_json( 1, 'Name of second Group Configuration', 'Second group configuration.', [ Group("0", 'Alpha'), Group("1", 'Beta'), Group("2", 'Gamma') ]), ], }, }) # 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': 1})) unit = ContainerPage(self.browser, vertical.locator) unit.visit() experiment = unit.xblocks[0] group_configuration_link_name = experiment.group_configuration_link_name experiment.go_to_group_configuration_page() self.page.wait_for_page() # Appropriate Group Configuration is expanded. self.assertFalse( self.page.experiment_group_configurations[0].is_expanded) self.assertTrue( self.page.experiment_group_configurations[1].is_expanded) self.assertEqual(group_configuration_link_name, self.page.experiment_group_configurations[1].name)
def test_easy_access_from_experiment(self): """ Scenario: When a Content Experiment uses a Group Configuration, ensure that the link to that Group Configuration works correctly. Given I have a course with two Group Configurations And Content Experiment is assigned to one Group Configuration Then I see a link to Group Configuration When I click on the Group Configuration link Then I see the Group Configurations page And I see that appropriate Group Configuration is expanded. """ # 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")] ), create_user_partition_json( 1, 'Name of second Group Configuration', 'Second group configuration.', [Group("0", 'Alpha'), Group("1", 'Beta'), Group("2", 'Gamma')] ), ], }, }) # 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': 1}) ) unit = ContainerPage(self.browser, vertical.locator) unit.visit() experiment = unit.xblocks[0] group_configuration_link_name = experiment.group_configuration_link_name experiment.go_to_group_configuration_page() self.page.wait_for_page() # Appropriate Group Configuration is expanded. self.assertFalse(self.page.experiment_group_configurations[0].is_expanded) self.assertTrue(self.page.experiment_group_configurations[1].is_expanded) self.assertEqual( group_configuration_link_name, self.page.experiment_group_configurations[1].name )
def setUp(self, is_staff=True): """ Create a course with a section, subsection, and unit to which to add the component. """ super(HTMLComponentEditorTests, self).setUp(is_staff=is_staff) self.unit = self.go_to_unit_page() self.container_page = ContainerPage(self.browser, None) self.xblock_wrapper = XBlockWrapper(self.browser, None) self.component = None self.html_editor = None self.iframe = None
def setUp(self, is_staff=True): """ Create a course with a section, subsection, and unit to which to add the component. """ super(DiscussionComponentTest, self).setUp(is_staff=is_staff) self.component = 'discussion' self.unit = self.go_to_unit_page() self.container_page = ContainerPage(self.browser, None) # Add Discussion component add_component(self.container_page, 'discussion', self.component) self.component = self.unit.xblocks[1] self.container_page.edit() self.discussion_editor = DiscussionComponentEditor(self.browser, self.component.locator)
def setUp(self, is_staff=True): """ Create a course with a section, subsection, and unit to which to add the component. """ super(ProblemComponentEditor, self).setUp(is_staff=is_staff) self.component = 'Blank Common Problem' self.unit = self.go_to_unit_page() self.container_page = ContainerPage(self.browser, None) # Add a Problem add_component(self.container_page, 'problem', self.component) self.component = self.unit.xblocks[1] self.container_page.edit() self.problem_editor = ProblemXBlockEditorView(self.browser, self.component.locator)
def test_split_test_LMS_staff_view(self): """ Scenario: Ensure that split test is correctly rendered in LMS staff mode as it is and after inactive group removal. Given I have a course with group configurations and split test that assigned to first group configuration Then I publish split test and view it in LMS in staff view And it is rendered correctly Then I go to group configuration and delete group Then I publish split test and view it in LMS in staff view And it is rendered correctly Then I go to split test and delete inactive vertical Then I publish unit and view unit in LMS in staff view And it is rendered correctly """ config, split_test = self.create_group_configuration_experiment([Group("0", "Group A"), Group("1", "Group B"), Group("2", "Group C")], True) container = ContainerPage(self.browser, split_test.locator) # render in LMS correctly courseware_page = CoursewarePage(self.browser, self.course_id) self.publish_unit_and_verify_groups_in_lms(courseware_page, [u'Group A', u'Group B', u'Group C']) # I go to group configuration and delete group self.page.visit() self.page.q(css='.group-toggle').first.click() config.edit() config.groups[2].remove() config.save() self.page.q(css='.group-toggle').first.click() self._assert_fields(config, name="Name", description="Description", groups=["Group A", "Group B"]) self.browser.close() self.browser.switch_to_window(self.browser.window_handles[0]) # render in LMS to see how inactive vertical is rendered self.publish_unit_and_verify_groups_in_lms( courseware_page, [u'Group A', u'Group B', u'Group ID 2 (inactive)'], publish=False ) self.browser.close() self.browser.switch_to_window(self.browser.window_handles[0]) # I go to split test and delete inactive vertical container.visit() container.delete(0) # render in LMS again self.publish_unit_and_verify_groups_in_lms(courseware_page, [u'Group A', u'Group B'])
def setUp(self, is_staff=True): """ Create a course with a section, subsection, and unit to which to add the component. """ super(HTMLComponentEditor, self).setUp(is_staff=is_staff) self.component = 'Text' self.unit = self.go_to_unit_page() self.container_page = ContainerPage(self.browser, None) self.xblock_wrapper = XBlockWrapper(self.browser, None) # Add HTML component add_component(self.container_page, 'html', self.component) self.component = self.unit.xblocks[1] self.container_page.edit() self.html_editor = HtmlXBlockEditorView(self.browser, self.component.locator) self.iframe = HTMLEditorIframe(self.browser, self.component.locator)
def test_add_html_component(self): """ Scenario: I can add HTML components Given I am in Studio editing a new unit When I add this type of HTML component: | Component | | Text | | Announcement | | Zooming Image Tool | | Raw HTML | Then I see HTML components in this order: | Component | | Text | | Announcement | | Zooming Image Tool | | Raw HTML | """ # Components to be added components = ['Text', 'Announcement', 'Zooming Image Tool', 'Raw HTML'] self.go_to_unit_page() container_page = ContainerPage(self.browser, None) # Add components add_components(container_page, 'html', components) problems = [x_block.name for x_block in container_page.xblocks[1:]] # Assert that components appear in same order as added. self.assertEqual(problems, components)
def test_common_problem_component(self): """ Scenario: I can add Common Problem components Given I am in Studio editing a new unit When I add this type of Problem component: | Component |` | Blank Common Problem | | Checkboxes | | Dropdown | | Multiple Choice | | Numerical Input | | Text Input | Then I see Problem components in this order: | Component | | Blank Common Problem | | Checkboxes | | Dropdown | | Multiple Choice | | Numerical Input | | Text Input | """ # Components to be added. components = ['Blank Common Problem', 'Checkboxes', 'Dropdown', 'Multiple Choice', 'Numerical Input', 'Text Input'] self.go_to_unit_page() container_page = ContainerPage(self.browser, None) # Add components add_components(container_page, 'problem', components) problems = [x_block.name for x_block in container_page.xblocks[1:]] # Assert that components appear in the same order as added. self.assertEqual(problems, components)
def test_add_latex_html_component(self): """ Scenario: I can add Latex HTML components Given I am in Studio editing a new unit Given I have enabled latex compiler When I add this type of HTML component: | Component | | E-text Written in LaTeX | Then I see HTML components in this order: | Component | | E-text Written in LaTeX | """ # Latex component component = 'E-text Written in LaTeX' # Visit advanced settings page and enable latex compiler. self.advanced_settings.visit() self.advanced_settings.set('Enable LaTeX Compiler', 'True') self.go_to_unit_page() container_page = ContainerPage(self.browser, None) # Add latex component add_component(container_page, 'html', component, is_advanced_problem=False) problem = container_page.xblocks[1] # Asset that component has been added. self.assertEqual(problem.name, component)
def setUp(self): # pylint: disable=arguments-differ super(TestCourseBadExport, self).setUp() self.export_page = ExportCoursePage( self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'], ) self.edit_page = ContainerPage(self.browser, self.unit.locator) self.export_page.visit()
def test_use_group_configuration(self): """ Scenario: Ensure that the group configuration can be used by split_module correctly Given I have a course without group configurations When I create new group configuration And I set new name and add a new group, save the group configuration And I go to the unit page in Studio And I add new advanced module "Content Experiment" When I assign created group configuration to the module Then I see the module has correct groups """ self.page.visit() # Create new group configuration self.page.create_experiment_group_configuration() config = self.page.experiment_group_configurations[0] config.name = "New Group Configuration Name" # Add new group config.add_group() config.groups[2].name = "New group" # Save the configuration config.save() split_test = self._add_split_test_to_vertical(number=0) container = ContainerPage(self.browser, split_test.locator) container.visit() container.edit() component_editor = XBlockEditorView(self.browser, container.locator) component_editor.set_select_value_and_save( 'Group Configuration', 'New Group Configuration Name') self.verify_groups(container, ['Group A', 'Group B', 'New group'], [])
def test_split_test_LMS_staff_view(self): """ Scenario: Ensure that split test is correctly rendered in LMS staff mode as it is and after inactive group removal. Given I have a course with group configurations and split test that assigned to first group configuration Then I publish split test and view it in LMS in staff view And it is rendered correctly Then I go to group configuration and delete group Then I publish split test and view it in LMS in staff view And it is rendered correctly Then I go to split test and delete inactive vertical Then I publish unit and view unit in LMS in staff view And it is rendered correctly """ config, split_test = self.create_group_configuration_experiment([ Group("0", "Group A"), Group("1", "Group B"), Group("2", "Group C") ], True) container = ContainerPage(self.browser, split_test.locator) # render in LMS correctly courseware_page = CoursewarePage(self.browser, self.course_id) self.publish_unit_and_verify_groups_in_lms( courseware_page, [u'Group A', u'Group B', u'Group C']) # I go to group configuration and delete group self.page.visit() self.page.q(css='.group-toggle').first.click() config.edit() config.groups[2].remove() config.save() self.page.q(css='.group-toggle').first.click() self._assert_fields(config, name="Name", description="Description", groups=["Group A", "Group B"]) self.browser.close() self.browser.switch_to_window(self.browser.window_handles[0]) # render in LMS to see how inactive vertical is rendered self.publish_unit_and_verify_groups_in_lms( courseware_page, [u'Group A', u'Group B', u'Group ID 2 (inactive)'], publish=False) self.browser.close() self.browser.switch_to_window(self.browser.window_handles[0]) # I go to split test and delete inactive vertical container.visit() container.delete(0) # render in LMS again self.publish_unit_and_verify_groups_in_lms(courseware_page, [u'Group A', u'Group B'])
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 _studio_add_content(self, studio_course_outline, html_content): """ Add content to first section on studio course page. """ # create a unit in course outline studio_course_outline.visit() subsection = studio_course_outline.section_at(0).subsection_at(0) subsection.expand_subsection() subsection.add_unit() # got to unit and create an HTML component and save (not publish) unit_page = ContainerPage(self.browser, None) unit_page.wait_for_page() add_html_component(unit_page, 0) unit_page.wait_for_element_presence('.edit-button', 'Edit button is visible') click_css(unit_page, '.edit-button', 0, require_notification=False) unit_page.wait_for_element_visibility('.modal-editor', 'Modal editor is visible') type_in_codemirror(unit_page, 0, html_content) click_css(unit_page, '.action-save', 0)
def _studio_add_content(self, section_index): """ Add content on studio course page under specified section """ self._auto_auth(self.STAFF_USERNAME, self.STAFF_EMAIL, True) # create a unit in course outline self.studio_course_outline.visit() subsection = self.studio_course_outline.section_at(section_index).subsection_at(0) subsection.expand_subsection() subsection.add_unit() # got to unit and create an HTML component and save (not publish) unit_page = ContainerPage(self.browser, None) unit_page.wait_for_page() add_html_component(unit_page, 0) unit_page.wait_for_element_presence('.edit-button', 'Edit button is visible') click_css(unit_page, '.edit-button', 0, require_notification=False) unit_page.wait_for_element_visibility('.modal-editor', 'Modal editor is visible') type_in_codemirror(unit_page, 0, self.HTML_CONTENT) click_css(unit_page, '.action-save', 0)
def test_add_advanced_problem(self, component): """ Scenario Outline: I can add Advanced Problem components Given I am in Studio editing a new unit When I add a "<Component>" "Advanced Problem" component Then I see a "<Component>" Problem component Examples: | Component | | Blank Advanced Problem | | Circuit Schematic Builder | | Custom Python-Evaluated Input | | Drag and Drop | | Image Mapped Input | | Math Expression Input | | Problem with Adaptive Hint | """ self.go_to_unit_page() page = ContainerPage(self.browser, None) add_component(page, 'problem', component, is_advanced_problem=True) problem = page.xblocks[1] self.assertEqual(problem.name, component)
class ProblemComponentEditor(ContainerBase): """ Feature: CMS.Component Adding As a course author, I want to be able to add and edit Problem """ def setUp(self, is_staff=True): """ Create a course with a section, subsection, and unit to which to add the component. """ super(ProblemComponentEditor, self).setUp(is_staff=is_staff) self.component = 'Blank Common Problem' self.unit = self.go_to_unit_page() self.container_page = ContainerPage(self.browser, None) # Add a Problem add_component(self.container_page, 'problem', self.component) self.component = self.unit.xblocks[1] self.container_page.edit() self.problem_editor = ProblemXBlockEditorView(self.browser, self.component.locator) def populate_course_fixture(self, course_fixture): """ Adds a course fixture """ course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc('vertical', 'Test Unit') ) ) ) def test_user_can_view_metadata(self): """ Scenario: User can view metadata Given I have created a Blank Common Problem When I edit and select Settings Then I see the advanced settings and their expected values And Edit High Level Source is not visible """ expected_default_settings = { 'Display Name': u'Blank Common Problem', 'Matlab API key': u'', 'Maximum Attempts': u'', 'Problem Weight': u'', 'Randomization': u'Never', 'Show Answer': u'Finished', 'Show Reset Button': u'False', 'Timer Between Attempts': u'0' } self.problem_editor.open_settings() settings = self.problem_editor.get_settings() self.assertEqual(expected_default_settings, settings) self.assertFalse(self.problem_editor.is_latex_compiler_present()) def test_user_can_modify_string_values(self): """ Given I have created a Blank Common Problem When I edit and select Settings Then I can modify the display name And my display name change is persisted on save """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Display Name', 'New Name') self.problem_editor.save() component_name = self.unit.xblock_titles[0] self.assertEqual(component_name, 'New Name', 'Component Name is not same as the new name') def test_user_can_specify_special_characters(self): """ Scenario: User can specify special characters in String values Given I have created a Blank Common Problem When I edit and select Settings Then I can specify special characters in the display name And my special characters are persisted on save """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Display Name', '&&&') self.problem_editor.save() component_name = self.unit.xblock_titles[0] self.assertEqual(component_name, '&&&', 'Component Name is not same as the new name') def test_user_can_revert_display_name_to_unset(self): """ Scenario: User can revert display name to unset Given I have created a Blank Common Problem When I edit and select Settings Then I can revert the display name to unset And my display name is unset on save """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Display Name', 'New Name') self.problem_editor.save() # reopen settings self.container_page.edit() self.problem_editor.open_settings() self.problem_editor.revert_setting(display_name=True) self.problem_editor.save() component_name = self.unit.xblock_titles[0] self.assertEqual(component_name, 'Blank Advanced Problem', 'Component Name is not reverted to default name') def test_user_can_set_html_in_display_name(self): """ Scenario: User can specify html in display name and it will be escaped Given I have created a Blank Common Problem When I edit and select Settings Then I can specify html in the display name and save And the problem display name is "<script>alert('test')</script>" """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Display Name', '<script>alert("test")</script>') self.problem_editor.save() component_name = self.unit.xblock_titles[0] self.assertEqual( component_name, '<script>alert("test")</script>', 'Component Name is not same as the new name' ) def test_user_can_modify_float_input(self): """ Scenario: User can modify float input values Given I have created a Blank Common Problem When I edit and select Settings Then I can set the weight to "3.5" And my change to weight is persisted And I can revert to the default value of unset for weight """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Problem Weight', '3.5') self.problem_editor.save() # reopen settings self.container_page.edit() self.problem_editor.open_settings() field_value = self.problem_editor.get_field_val('Problem Weight') self.assertEqual(field_value, '3.5') self.problem_editor.revert_setting() field_value = self.problem_editor.get_field_val('Problem Weight') self.assertEqual(field_value, '', 'Component settings is not reverted to default') def test_user_cannot_type_letters(self): """ Scenario: User cannot type letters in float number field Given I have created a Blank Common Problem When I edit and select Settings Then if I set the weight to "abc", it remains unset """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Problem Weight', 'abc') field_value = self.problem_editor.get_field_val('Problem Weight') self.assertEqual(field_value, '', "Only the Numerical input is allowed in this field") @skip_if_browser('firefox') # Lettuce tests run on chrome and chrome does not allow to enter # periods/dots in this field and consequently we have to save the # value as '234'. Whereas, bokchoy runs with the older version of # firefox on jenkins, which does not allow to save the value if it # has a period/dot. Clicking on save button after filling '2.34' in # field, does not do anything and test does not go any further. # So, it fails always. def test_user_cannot_type_decimal_values(self): """ Scenario: User cannot type decimal values integer number field Given I have created a Blank Common Problem When I edit and select Settings Then if I set the max attempts to "2.34", it will persist as a valid integer """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Maximum Attempts', '2.34') self.problem_editor.save() # reopen settings self.container_page.edit() self.problem_editor.open_settings() field_value = self.problem_editor.get_field_val('Maximum Attempts') self.assertEqual(field_value, '234', "Decimal values are not allowed in this field") def test_user_cannot_type_out_of_range_values(self): """ Scenario: User cannot type out of range values in an integer number field Given I have created a Blank Common Problem When I edit and select Settings Then if I set the max attempts to "-3", it will persist as a valid integer """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Maximum Attempts', '-3') self.problem_editor.save() # reopen settings self.container_page.edit() self.problem_editor.open_settings() field_value = self.problem_editor.get_field_val('Maximum Attempts') self.assertGreaterEqual(field_value, '0', "Negative values are not allowed in this field") def test_settings_are_not_saved_on_cancel(self): """ Scenario: Settings changes are not saved on Cancel Given I have created a Blank Common Problem When I edit and select Settings Then I can set the weight to "3.5" And I can modify the display name Then If I press Cancel my changes are not persisted """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Problem Weight', '3.5') self.problem_editor.cancel() # reopen settings self.container_page.edit() self.problem_editor.open_settings() field_value = self.problem_editor.get_field_val('Problem Weight') self.assertEqual(field_value, '', "Component setting should not appear updated if cancelled during editing") def test_cheat_sheet_visible_on_toggle(self): """ Scenario: Cheat sheet visible on toggle Given I have created a Blank Common Problem And I can edit the problem Then I can see cheatsheet """ self.problem_editor.toggle_cheatsheet() self.assertTrue(self.problem_editor.is_cheatsheet_present(), "Cheatsheet not present") def test_user_can_select_values(self): """ Scenario: User can select values in a Select Given I have created a Blank Common Problem When I edit and select Settings Then I can select 'Per Student' for Randomization And my change to randomization is persisted And I can revert to the default value for randomization """ dropdown_name = 'Randomization' self.problem_editor.open_settings() self.problem_editor.select_from_dropdown(dropdown_name, 'Per Student') self.problem_editor.save() # reopen the settings self.container_page.edit() self.problem_editor.open_settings() dropdown_value = self.problem_editor.get_value_from_the_dropdown(dropdown_name) self.assertEqual(dropdown_value, 'Per Student', "Component setting is not changed") # revert settings self.problem_editor.revert_setting() dropdown_value = self.problem_editor.get_value_from_the_dropdown(dropdown_name) self.assertEqual(dropdown_value, 'Never', 'Component setting is not reverted to default')
class ProblemComponentEditor(ContainerBase): """ Feature: CMS.Component Adding As a course author, I want to be able to add and edit Problem """ def setUp(self, is_staff=True): """ Create a course with a section, subsection, and unit to which to add the component. """ super(ProblemComponentEditor, self).setUp(is_staff=is_staff) self.component = 'Blank Common Problem' self.unit = self.go_to_unit_page() self.container_page = ContainerPage(self.browser, None) # Add a Problem add_component(self.container_page, 'problem', self.component) self.component = self.unit.xblocks[1] self.container_page.edit() self.problem_editor = ProblemXBlockEditorView(self.browser, self.component.locator) def populate_course_fixture(self, course_fixture): """ Adds a course fixture """ course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc('vertical', 'Test Unit') ) ) ) def test_user_can_view_metadata(self): """ Scenario: User can view metadata Given I have created a Blank Common Problem When I edit and select Settings Then I see the advanced settings and their expected values And Edit High Level Source is not visible """ expected_default_settings = { 'Display Name': u'Blank Common Problem', 'Matlab API key': u'', 'Maximum Attempts': u'', 'Problem Weight': u'', 'Randomization': u'Never', 'Show Answer': u'Finished', 'Show Answer: Number of Attempts': u'0', 'Show Reset Button': u'False', 'Timer Between Attempts': u'0' } self.problem_editor.open_settings() settings = self.problem_editor.get_settings() self.assertEqual(expected_default_settings, settings) self.assertFalse(self.problem_editor.is_latex_compiler_present()) def test_user_can_modify_string_values(self): """ Given I have created a Blank Common Problem When I edit and select Settings Then I can modify the display name And my display name change is persisted on save """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Display Name', 'New Name') self.problem_editor.save() component_name = self.unit.xblock_titles[0] self.assertEqual(component_name, 'New Name', 'Component Name is not same as the new name') def test_user_can_specify_special_characters(self): """ Scenario: User can specify special characters in String values Given I have created a Blank Common Problem When I edit and select Settings Then I can specify special characters in the display name And my special characters are persisted on save """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Display Name', '&&&') self.problem_editor.save() component_name = self.unit.xblock_titles[0] self.assertEqual(component_name, '&&&', 'Component Name is not same as the new name') def test_user_can_revert_display_name_to_unset(self): """ Scenario: User can revert display name to unset Given I have created a Blank Common Problem When I edit and select Settings Then I can revert the display name to unset And my display name is unset on save """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Display Name', 'New Name') self.problem_editor.save() # reopen settings self.container_page.edit() self.problem_editor.open_settings() self.problem_editor.revert_setting(display_name=True) self.problem_editor.save() component_name = self.unit.xblock_titles[0] self.assertEqual(component_name, 'Blank Advanced Problem', 'Component Name is not reverted to default name') def test_user_can_set_html_in_display_name(self): """ Scenario: User can specify html in display name and it will be escaped Given I have created a Blank Common Problem When I edit and select Settings Then I can specify html in the display name and save And the problem display name is "<script>alert('test')</script>" """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Display Name', '<script>alert("test")</script>') self.problem_editor.save() component_name = self.unit.xblock_titles[0] self.assertEqual( component_name, '<script>alert("test")</script>', 'Component Name is not same as the new name' ) def test_user_can_modify_float_input(self): """ Scenario: User can modify float input values Given I have created a Blank Common Problem When I edit and select Settings Then I can set the weight to "3.5" And my change to weight is persisted And I can revert to the default value of unset for weight """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Problem Weight', '3.5') self.problem_editor.save() # reopen settings self.container_page.edit() self.problem_editor.open_settings() field_value = self.problem_editor.get_field_val('Problem Weight') self.assertEqual(field_value, '3.5') self.problem_editor.revert_setting() field_value = self.problem_editor.get_field_val('Problem Weight') self.assertEqual(field_value, '', 'Component settings is not reverted to default') def test_user_cannot_type_letters(self): """ Scenario: User cannot type letters in float number field Given I have created a Blank Common Problem When I edit and select Settings Then if I set the weight to "abc", it remains unset """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Problem Weight', 'abc') field_value = self.problem_editor.get_field_val('Problem Weight') self.assertEqual(field_value, '', "Only the Numerical input is allowed in this field") @skip_if_browser('firefox') # Lettuce tests run on chrome and chrome does not allow to enter # periods/dots in this field and consequently we have to save the # value as '234'. Whereas, bokchoy runs with the older version of # firefox on jenkins, which does not allow to save the value if it # has a period/dot. Clicking on save button after filling '2.34' in # field, does not do anything and test does not go any further. # So, it fails always. def test_user_cannot_type_decimal_values(self): """ Scenario: User cannot type decimal values integer number field Given I have created a Blank Common Problem When I edit and select Settings Then if I set the max attempts to "2.34", it will persist as a valid integer """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Maximum Attempts', '2.34') self.problem_editor.save() # reopen settings self.container_page.edit() self.problem_editor.open_settings() field_value = self.problem_editor.get_field_val('Maximum Attempts') self.assertEqual(field_value, '234', "Decimal values are not allowed in this field") def test_user_cannot_type_out_of_range_values(self): """ Scenario: User cannot type out of range values in an integer number field Given I have created a Blank Common Problem When I edit and select Settings Then if I set the max attempts to "-3", it will persist as a valid integer """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Maximum Attempts', '-3') self.problem_editor.save() # reopen settings self.container_page.edit() self.problem_editor.open_settings() field_value = self.problem_editor.get_field_val('Maximum Attempts') self.assertGreaterEqual(field_value, '0', "Negative values are not allowed in this field") def test_settings_are_not_saved_on_cancel(self): """ Scenario: Settings changes are not saved on Cancel Given I have created a Blank Common Problem When I edit and select Settings Then I can set the weight to "3.5" And I can modify the display name Then If I press Cancel my changes are not persisted """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Problem Weight', '3.5') self.problem_editor.cancel() # reopen settings self.container_page.edit() self.problem_editor.open_settings() field_value = self.problem_editor.get_field_val('Problem Weight') self.assertEqual(field_value, '', "Component setting should not appear updated if cancelled during editing") def test_cheat_sheet_visible_on_toggle(self): """ Scenario: Cheat sheet visible on toggle Given I have created a Blank Common Problem And I can edit the problem Then I can see cheatsheet """ self.problem_editor.toggle_cheatsheet() self.assertTrue(self.problem_editor.is_cheatsheet_present(), "Cheatsheet not present") def test_user_can_select_values(self): """ Scenario: User can select values in a Select Given I have created a Blank Common Problem When I edit and select Settings Then I can select 'Per Student' for Randomization And my change to randomization is persisted And I can revert to the default value for randomization """ dropdown_name = 'Randomization' self.problem_editor.open_settings() self.problem_editor.select_from_dropdown(dropdown_name, 'Per Student') self.problem_editor.save() # reopen the settings self.container_page.edit() self.problem_editor.open_settings() dropdown_value = self.problem_editor.get_value_from_the_dropdown(dropdown_name) self.assertEqual(dropdown_value, 'Per Student', "Component setting is not changed") # revert settings self.problem_editor.revert_setting() dropdown_value = self.problem_editor.get_value_from_the_dropdown(dropdown_name) self.assertEqual(dropdown_value, 'Never', 'Component setting is not reverted to default')
def test_container_page_active_verticals_names_are_synced(self): """ Scenario: Ensure that the Content Experiment display synced vertical names and correct groups. Given I have a course with group configuration And I go to the Group Configuration page in Studio And I edit the name of the group configuration, add new group and remove old one And I change the name for the group "New group" to "Second Group" And I go to the Container page in Studio And I edit the Content Experiment Then I see the group configuration name is changed in `Group Configuration` dropdown And the group configuration name is changed on container page And I see the module has 2 active groups and one inactive And I see "Add missing groups" link exists When I click on "Add missing groups" link The I see the module has 3 active groups and one inactive """ self.course_fixture._update_xblock(self.course_fixture._course_location, { "metadata": { u"user_partitions": [ create_user_partition_json( 0, 'Name of the Group Configuration', 'Description of the group configuration.', [Group("0", 'Group A'), Group("1", 'Group B'), Group("2", 'Group C')] ), ], }, }) # Add split test to vertical and assign newly created group configuration to it split_test = self._add_split_test_to_vertical(number=0, group_configuration_metadata={'user_partition_id': 0}) self.page.visit() config = self.page.experiment_group_configurations[0] config.edit() config.name = "Second Group Configuration Name" # `Group C` -> `Second Group` config.groups[2].name = "Second Group" # Add new group config.add_group() # Group D # Remove Group A config.groups[0].remove() # Save the configuration config.save() container = ContainerPage(self.browser, split_test.locator) container.visit() container.edit() component_editor = ComponentEditorView(self.browser, container.locator) self.assertEqual( "Second Group Configuration Name", component_editor.get_selected_option_text('Group Configuration') ) component_editor.cancel() self.assertIn( "Second Group Configuration Name", container.get_xblock_information_message() ) self.verify_groups( container, ['Group B', 'Second Group'], ['Group ID 0'], verify_missing_groups_not_present=False ) # Click the add button and verify that the groups were added on the page container.add_missing_groups() self.verify_groups(container, ['Group B', 'Second Group', 'Group D'], ['Group ID 0'])
def test_container_page_active_verticals_names_are_synced(self): """ Scenario: Ensure that the Content Experiment display synced vertical names and correct groups. Given I have a course with group configuration And I go to the Group Configuration page in Studio And I edit the name of the group configuration, add new group and remove old one And I change the name for the group "New group" to "Second Group" And I go to the Container page in Studio And I edit the Content Experiment Then I see the group configuration name is changed in `Group Configuration` dropdown And the group configuration name is changed on container page And I see the module has 2 active groups and one inactive And I see "Add missing groups" link exists When I click on "Add missing groups" link The I see the module has 3 active groups and one inactive """ self.course_fixture._update_xblock( self.course_fixture._course_location, { "metadata": { u"user_partitions": [ create_user_partition_json( 0, 'Name of the Group Configuration', 'Description of the group configuration.', [ Group("0", 'Group A'), Group("1", 'Group B'), Group("2", 'Group C') ]), ], }, }) # Add split test to vertical and assign newly created group configuration to it split_test = self._add_split_test_to_vertical( number=0, group_configuration_metadata={'user_partition_id': 0}) self.page.visit() config = self.page.experiment_group_configurations[0] config.edit() config.name = "Second Group Configuration Name" # `Group C` -> `Second Group` config.groups[2].name = "Second Group" # Add new group config.add_group() # Group D # Remove Group A config.groups[0].remove() # Save the configuration config.save() container = ContainerPage(self.browser, split_test.locator) container.visit() container.edit() component_editor = XBlockEditorView(self.browser, container.locator) self.assertEqual( "Second Group Configuration Name", component_editor.get_selected_option_text('Group Configuration')) component_editor.cancel() self.assertIn("Second Group Configuration Name", container.get_xblock_information_message()) self.verify_groups(container, ['Group B', 'Second Group'], ['Group ID 0'], verify_missing_groups_not_present=False) # Click the add button and verify that the groups were added on the page container.add_missing_groups() self.verify_groups(container, ['Group B', 'Second Group', 'Group D'], ['Group ID 0'])
class HTMLComponentEditorTests(ContainerBase): """ Feature: CMS.Component Adding As a course author, I want to be able to add and edit HTML component """ shard = 18 def setUp(self, is_staff=True): """ Create a course with a section, subsection, and unit to which to add the component. """ super(HTMLComponentEditorTests, self).setUp(is_staff=is_staff) self.unit = self.go_to_unit_page() self.container_page = ContainerPage(self.browser, None) self.xblock_wrapper = XBlockWrapper(self.browser, None) self.component = None self.html_editor = None self.iframe = None def populate_course_fixture(self, course_fixture): """ Adds a course fixture """ course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc('vertical', 'Test Unit') ) ) ) def _add_content(self, content): """ Set and save content in editor and assert its presence in container page's html Args: content(str): Verifiable content """ self.html_editor.set_raw_content(content) self.html_editor.save_content() self.container_page.wait_for_page() def _add_component(self, sub_type): """ Add sub-type of HTML component in studio Args: sub_type(str): Sub-type of HTML component """ add_component(self.container_page, 'html', sub_type) self.component = self.unit.xblocks[1] self.html_editor = HtmlXBlockEditorView(self.browser, self.component.locator) self.iframe = HTMLEditorIframe(self.browser, self.component.locator) def test_user_can_view_metadata(self): """ Scenario: User can view metadata Given I have created a Blank HTML Page And I edit and select Settings Then I see the HTML component settings """ # Add HTML Text type component self._add_component('Text') self.container_page.edit() self.html_editor.open_settings_tab() display_name_value = self.html_editor.get_default_settings()[0] display_name_key = self.html_editor.keys[0] self.assertEqual( ['Display Name', 'Text'], [display_name_key, display_name_value], "Settings not found" ) editor_value = self.html_editor.get_default_settings()[1] editor_key = self.html_editor.keys[1] self.assertEqual( ['Editor', 'Visual'], [editor_key, editor_value], "Settings not found" ) def test_user_can_modify_display_name(self): """ Scenario: User can modify display name Given I have created a Blank HTML Page And I edit and select Settings Then I can modify the display name And my display name change is persisted on save """ # Add HTML Text type component self._add_component('Text') self.container_page.edit() self.html_editor.open_settings_tab() self.html_editor.set_field_val('Display Name', 'New Name') self.html_editor.save_settings() component_name = self.unit.xblock_titles[0] self.assertEqual(component_name, 'New Name', "Component name is not as edited") def test_link_plugin_sets_url_correctly(self): """ Scenario: TinyMCE link plugin sets urls correctly Given I have created a Blank HTML Page When I edit the page And I add a link with static link "/static/image.jpg" via the Link Plugin Icon Then the href link is rewritten to the asset link "image.jpg" And the link is shown as "/static/image.jpg" in the Link Plugin """ static_link = '/static/image.jpg' # Add HTML Text type component self._add_component('Text') self.container_page.edit() self.html_editor.open_link_plugin() self.html_editor.save_static_link(static_link) self.html_editor.switch_to_iframe() href = self.iframe.href self.assertIn('image.jpg', href) self.iframe.select_link() self.iframe.switch_to_default() self.assertEqual( self.html_editor.url_from_the_link_plugin, static_link, "URL in the link plugin is different" ) def test_tinymce_and_codemirror_preserve_style_tags(self): """ Scenario: TinyMCE and CodeMirror preserve style tags Given I have created a Blank HTML Page When I edit the page And type "<p class='title'>pages</p><style><!-- .title { color: red; } --></style>" in the code editor and press OK And I save the page Then the page text contains: "" <p class="title">pages</p> <style><!-- .title { color: red; } --></style> "" """ content = u'<p class="title">pages</p><style><!-- .title { color: red; } --></style>' # Add HTML Text type component self._add_component('Text') self.container_page.edit() self._add_content(content) html = self.container_page.content_html self.assertIn(content, html) def test_tinymce_and_codemirror_preserve_span_tags(self): """ Scenario: TinyMCE and CodeMirror preserve span tags Given I have created a Blank HTML Page When I edit the page And type "<span>Test</span>" in the code editor and press OK And I save the page Then the page text contains: "" <span>Test</span> "" """ content = "<span>Test</span>" # Add HTML Text type component self._add_component('Text') self.container_page.edit() self._add_content(content) html = self.container_page.content_html self.assertIn(content, html) def test_tinymce_and_codemirror_preserve_math_tags(self): """ Scenario: TinyMCE and CodeMirror preserve math tags Given I have created a Blank HTML Page When I edit the page And type "<math><msup><mi>x</mi><mn>2</mn></msup></math>" in the code editor and press OK And I save the page Then the page text contains: "" <math><msup><mi>x</mi><mn>2</mn></msup></math> "" """ content = "<math><msup><mi>x</mi><mn>2</mn></msup></math>" # Add HTML Text type component self._add_component('Text') self.container_page.edit() self._add_content(content) html = self.container_page.content_html self.assertIn(content, html) def test_code_format_toolbar_wraps_text_with_code_tags(self): """ Scenario: Code format toolbar button wraps text with code tags Given I have created a Blank HTML Page When I edit the page And I set the text to "display as code" and I select the text And I save the page Then the page text contains: "" <p><code>display as code</code></p> "" """ # Add HTML Text type component self._add_component('Text') self.container_page.edit() self.html_editor.set_text_and_select("display as code") self.html_editor.click_code_toolbar_button() self.html_editor.save_content() html = self.container_page.content_html self.assertIn(html, '<p><code>display as code</code></p>') def test_raw_html_component_does_not_change_text(self): """ Scenario: Raw HTML component does not change text Given I have created a raw HTML component When I edit the page And type "<li>zzzz<ol> " into the Raw Editor And I save the page Then the page text contains: "" <li>zzzz<ol> "" And I edit the page Then the Raw Editor contains exactly: "" <li>zzzz<ol> "" """ content = "<li>zzzz</li>" # Add Raw HTML type component self._add_component('Raw HTML') self.container_page.edit() # Set content in tinymce editor type_in_codemirror(self.html_editor, 0, content) self.html_editor.save_content() # The HTML of the content added through tinymce editor html = self.container_page.content_html # The text content should be present with its tag preserved self.assertIn(content, html) self.container_page.edit() editor_value = self.html_editor.editor_value # The tinymce editor value should not be different from the content added in the start self.assertEqual(content, editor_value) def test_tinymce_toolbar_buttons_are_as_expected(self): """ Scenario: TinyMCE toolbar buttons are as expected Given I have created a Blank HTML Page When I edit the page Then the expected toolbar buttons are displayed """ # Add HTML Text type component self._add_component('Text') self.container_page.edit() expected_buttons = [ u'bold', u'italic', u'underline', u'forecolor', # This is our custom "code style" button, which uses an image instead of a class. u'none', u'alignleft', u'aligncenter', u'alignright', u'alignjustify', u'bullist', u'numlist', u'outdent', u'indent', u'blockquote', u'link', u'unlink', u'image' ] toolbar_dropdowns = self.html_editor.toolbar_dropdown_titles # The toolbar is divided in two sections: drop-downs and all other formatting buttons # The assertions under asserts for the drop-downs self.assertEqual(len(toolbar_dropdowns), 2) self.assertEqual(['Paragraph', 'Font Family'], toolbar_dropdowns) toolbar_buttons = self.html_editor.toolbar_button_titles # The assertions under asserts for all the remaining formatting buttons self.assertEqual(len(toolbar_buttons), len(expected_buttons)) for index, button in enumerate(expected_buttons): class_name = toolbar_buttons[index] self.assertEqual("mce-ico mce-i-" + button, class_name) def test_static_links_converted(self): """ Scenario: Static links are converted when switching between code editor and WYSIWYG views Given I have created a Blank HTML Page When I edit the page And type "<img src="/static/image.jpg">" in the code editor and press OK Then the src link is rewritten to the asset link /asset-v1:(course_id)+type@asset+block/image.jpg And the code editor displays "<p><img src="/static/image.jpg" /></p>" """ value = '<img src="/static/image.jpg">' # Add HTML Text type component self._add_component('Text') self.container_page.edit() self.html_editor.set_raw_content(value) self.html_editor.save_content() html = self.container_page.content_html src = "/asset-v1:{}+type@asset+block/image.jpg".format(self.course_id.strip('course-v1:')) self.assertIn(src, html) self.container_page.edit() self.html_editor.open_raw_editor() editor_value = self.html_editor.editor_value self.assertEqual(value, editor_value) def test_font_selection_dropdown(self): """ Scenario: Font selection dropdown contains Default font and tinyMCE builtin fonts Given I have created a Blank HTML Page When I edit the page And I click font selection dropdown Then I should see a list of available fonts And "Default" fonts should be available And all standard tinyMCE fonts should be available """ # Add HTML Text type component self._add_component('Text') self.container_page.edit() EXPECTED_FONTS = { u"Default": [u'"Open Sans"', u'Verdana', u'Arial', u'Helvetica', u'sans-serif'], u"Andale Mono": [u'andale mono', u'times'], u"Arial": [u'arial', u'helvetica', u'sans-serif'], u"Arial Black": [u'arial black', u'avant garde'], u"Book Antiqua": [u'book antiqua', u'palatino'], u"Comic Sans MS": [u'comic sans ms', u'sans-serif'], u"Courier New": [u'courier new', u'courier'], u"Georgia": [u'georgia', u'palatino'], u"Helvetica": [u'helvetica'], u"Impact": [u'impact', u'chicago'], u"Symbol": [u'symbol'], u"Tahoma": [u'tahoma', u'arial', u'helvetica', u'sans-serif'], u"Terminal": [u'terminal', u'monaco'], u"Times New Roman": [u'times new roman', u'times'], u"Trebuchet MS": [u'trebuchet ms', u'geneva'], u"Verdana": [u'verdana', u'geneva'], # tinyMCE does not set font-family on dropdown span for these two fonts u"Webdings": [u""], # webdings u"Wingdings": [u""] # wingdings } self.html_editor.open_font_dropdown() self.assertDictContainsSubset(EXPECTED_FONTS, self.html_editor.font_dict())
class HTMLComponentEditorTests(ContainerBase): """ Feature: CMS.Component Adding As a course author, I want to be able to add and edit HTML component """ shard = 18 def setUp(self, is_staff=True): """ Create a course with a section, subsection, and unit to which to add the component. """ super(HTMLComponentEditorTests, self).setUp(is_staff=is_staff) self.unit = self.go_to_unit_page() self.container_page = ContainerPage(self.browser, None) self.xblock_wrapper = XBlockWrapper(self.browser, None) self.component = None self.html_editor = None self.iframe = None def populate_course_fixture(self, course_fixture): """ Adds a course fixture """ course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc( 'vertical', 'Test Unit')))) def _add_content(self, content): """ Set and save content in editor and assert its presence in container page's html Args: content(str): Verifiable content """ self.html_editor.set_raw_content(content) self.html_editor.save_content() self.container_page.wait_for_page() def _add_component(self, sub_type): """ Add sub-type of HTML component in studio Args: sub_type(str): Sub-type of HTML component """ add_component(self.container_page, 'html', sub_type) self.component = self.unit.xblocks[1] self.html_editor = HtmlXBlockEditorView(self.browser, self.component.locator) self.iframe = HTMLEditorIframe(self.browser, self.component.locator) def test_user_can_view_metadata(self): """ Scenario: User can view metadata Given I have created a Blank HTML Page And I edit and select Settings Then I see the HTML component settings """ # Add HTML Text type component self._add_component('Text') self.container_page.edit() self.html_editor.open_settings_tab() display_name_value = self.html_editor.get_default_settings()[0] display_name_key = self.html_editor.keys[0] self.assertEqual(['Display Name', 'Text'], [display_name_key, display_name_value], "Settings not found") editor_value = self.html_editor.get_default_settings()[1] editor_key = self.html_editor.keys[1] self.assertEqual(['Editor', 'Visual'], [editor_key, editor_value], "Settings not found") def test_user_can_modify_display_name(self): """ Scenario: User can modify display name Given I have created a Blank HTML Page And I edit and select Settings Then I can modify the display name And my display name change is persisted on save """ # Add HTML Text type component self._add_component('Text') self.container_page.edit() self.html_editor.open_settings_tab() self.html_editor.set_field_val('Display Name', 'New Name') self.html_editor.save_settings() component_name = self.unit.xblock_titles[0] self.assertEqual(component_name, 'New Name', "Component name is not as edited") def test_link_plugin_sets_url_correctly(self): """ Scenario: TinyMCE link plugin sets urls correctly Given I have created a Blank HTML Page When I edit the page And I add a link with static link "/static/image.jpg" via the Link Plugin Icon Then the href link is rewritten to the asset link "image.jpg" And the link is shown as "/static/image.jpg" in the Link Plugin """ static_link = '/static/image.jpg' # Add HTML Text type component self._add_component('Text') self.container_page.edit() self.html_editor.open_link_plugin() self.html_editor.save_static_link(static_link) self.html_editor.switch_to_iframe() href = self.iframe.href self.assertIn('image.jpg', href) self.iframe.select_link() self.iframe.switch_to_default() self.assertEqual(self.html_editor.url_from_the_link_plugin, static_link, "URL in the link plugin is different") def test_tinymce_and_codemirror_preserve_style_tags(self): """ Scenario: TinyMCE and CodeMirror preserve style tags Given I have created a Blank HTML Page When I edit the page And type "<p class='title'>pages</p><style><!-- .title { color: red; } --></style>" in the code editor and press OK And I save the page Then the page text contains: "" <p class="title">pages</p> <style><!-- .title { color: red; } --></style> "" """ content = u'<p class="title">pages</p><style><!-- .title { color: red; } --></style>' # Add HTML Text type component self._add_component('Text') self.container_page.edit() self._add_content(content) html = self.container_page.content_html self.assertIn(content, html) def test_tinymce_and_codemirror_preserve_span_tags(self): """ Scenario: TinyMCE and CodeMirror preserve span tags Given I have created a Blank HTML Page When I edit the page And type "<span>Test</span>" in the code editor and press OK And I save the page Then the page text contains: "" <span>Test</span> "" """ content = "<span>Test</span>" # Add HTML Text type component self._add_component('Text') self.container_page.edit() self._add_content(content) html = self.container_page.content_html self.assertIn(content, html) def test_tinymce_and_codemirror_preserve_math_tags(self): """ Scenario: TinyMCE and CodeMirror preserve math tags Given I have created a Blank HTML Page When I edit the page And type "<math><msup><mi>x</mi><mn>2</mn></msup></math>" in the code editor and press OK And I save the page Then the page text contains: "" <math><msup><mi>x</mi><mn>2</mn></msup></math> "" """ content = "<math><msup><mi>x</mi><mn>2</mn></msup></math>" # Add HTML Text type component self._add_component('Text') self.container_page.edit() self._add_content(content) html = self.container_page.content_html self.assertIn(content, html) def test_code_format_toolbar_wraps_text_with_code_tags(self): """ Scenario: Code format toolbar button wraps text with code tags Given I have created a Blank HTML Page When I edit the page And I set the text to "display as code" and I select the text And I save the page Then the page text contains: "" <p><code>display as code</code></p> "" """ # Add HTML Text type component self._add_component('Text') self.container_page.edit() self.html_editor.set_text_and_select("display as code") self.html_editor.click_code_toolbar_button() self.html_editor.save_content() html = self.container_page.content_html self.assertIn(html, '<p><code>display as code</code></p>') def test_raw_html_component_does_not_change_text(self): """ Scenario: Raw HTML component does not change text Given I have created a raw HTML component When I edit the page And type "<li>zzzz<ol> " into the Raw Editor And I save the page Then the page text contains: "" <li>zzzz<ol> "" And I edit the page Then the Raw Editor contains exactly: "" <li>zzzz<ol> "" """ content = "<li>zzzz</li>" # Add Raw HTML type component self._add_component('Raw HTML') self.container_page.edit() # Set content in tinymce editor type_in_codemirror(self.html_editor, 0, content) self.html_editor.save_content() # The HTML of the content added through tinymce editor html = self.container_page.content_html # The text content should be present with its tag preserved self.assertIn(content, html) self.container_page.edit() editor_value = self.html_editor.editor_value # The tinymce editor value should not be different from the content added in the start self.assertEqual(content, editor_value) def test_tinymce_toolbar_buttons_are_as_expected(self): """ Scenario: TinyMCE toolbar buttons are as expected Given I have created a Blank HTML Page When I edit the page Then the expected toolbar buttons are displayed """ # Add HTML Text type component self._add_component('Text') self.container_page.edit() expected_buttons = [ u'bold', u'italic', u'underline', u'forecolor', # This is our custom "code style" button, which uses an image instead of a class. u'none', u'alignleft', u'aligncenter', u'alignright', u'alignjustify', u'bullist', u'numlist', u'outdent', u'indent', u'blockquote', u'link', u'unlink', u'image' ] toolbar_dropdowns = self.html_editor.toolbar_dropdown_titles # The toolbar is divided in two sections: drop-downs and all other formatting buttons # The assertions under asserts for the drop-downs self.assertEqual(len(toolbar_dropdowns), 2) self.assertEqual(['Paragraph', 'Font Family'], toolbar_dropdowns) toolbar_buttons = self.html_editor.toolbar_button_titles # The assertions under asserts for all the remaining formatting buttons self.assertEqual(len(toolbar_buttons), len(expected_buttons)) for index, button in enumerate(expected_buttons): class_name = toolbar_buttons[index] self.assertEqual("mce-ico mce-i-" + button, class_name) def test_static_links_converted(self): """ Scenario: Static links are converted when switching between code editor and WYSIWYG views Given I have created a Blank HTML Page When I edit the page And type "<img src="/static/image.jpg">" in the code editor and press OK Then the src link is rewritten to the asset link /asset-v1:(course_id)+type@asset+block/image.jpg And the code editor displays "<p><img src="/static/image.jpg" /></p>" """ value = '<img src="/static/image.jpg">' # Add HTML Text type component self._add_component('Text') self.container_page.edit() self.html_editor.set_raw_content(value) self.html_editor.save_content() html = self.container_page.content_html src = "/asset-v1:{}+type@asset+block/image.jpg".format( self.course_id.strip('course-v1:')) self.assertIn(src, html) self.container_page.edit() self.html_editor.open_raw_editor() editor_value = self.html_editor.editor_value self.assertEqual(value, editor_value) def test_font_selection_dropdown(self): """ Scenario: Font selection dropdown contains Default font and tinyMCE builtin fonts Given I have created a Blank HTML Page When I edit the page And I click font selection dropdown Then I should see a list of available fonts And "Default" fonts should be available And all standard tinyMCE fonts should be available """ # Add HTML Text type component self._add_component('Text') self.container_page.edit() EXPECTED_FONTS = { u"Default": [ u'"Open Sans"', u'Verdana', u'Arial', u'Helvetica', u'sans-serif' ], u"Andale Mono": [u'andale mono', u'times'], u"Arial": [u'arial', u'helvetica', u'sans-serif'], u"Arial Black": [u'arial black', u'avant garde'], u"Book Antiqua": [u'book antiqua', u'palatino'], u"Comic Sans MS": [u'comic sans ms', u'sans-serif'], u"Courier New": [u'courier new', u'courier'], u"Georgia": [u'georgia', u'palatino'], u"Helvetica": [u'helvetica'], u"Impact": [u'impact', u'chicago'], u"Symbol": [u'symbol'], u"Tahoma": [u'tahoma', u'arial', u'helvetica', u'sans-serif'], u"Terminal": [u'terminal', u'monaco'], u"Times New Roman": [u'times new roman', u'times'], u"Trebuchet MS": [u'trebuchet ms', u'geneva'], u"Verdana": [u'verdana', u'geneva'], # tinyMCE does not set font-family on dropdown span for these two fonts u"Webdings": [u""], # webdings u"Wingdings": [u""] # wingdings } self.html_editor.open_font_dropdown() self.assertDictContainsSubset(EXPECTED_FONTS, self.html_editor.font_dict()) def test_image_modal(self): """ Scenario: TinyMCE text editor allows to add multiple images. Given I have created a Blank text editor Page. I add an image in TinyMCE text editor and hit save button. I edit the component again. I add another image in TinyMCE text editor and hit save button again. Then it is expected that both images show up on page. """ image_file_names = [u'file-0.png', u'file-1.png'] self._add_component('Text') for image in image_file_names: image_path = os.path.join(UPLOAD_FILE_DIR, image) self.container_page.edit() self.html_editor.open_image_modal() self.html_editor.upload_image(image_path) self.html_editor.save_content() self.html_editor.wait_for_ajax() self.container_page.edit() self.html_editor.open_raw_editor() editor_value = self.html_editor.editor_value number_of_images = editor_value.count(u'img') self.assertEqual(number_of_images, 2)
def go_to(self): """ Open the container page linked to by this unit link, and return an initialized :class:`.ContainerPage` for that unit. """ return ContainerPage(self.browser, self.locator).visit()
class HTMLComponentEditor(ContainerBase): """ Feature: CMS.Component Adding As a course author, I want to be able to add and edit HTML component """ def setUp(self, is_staff=True): """ Create a course with a section, subsection, and unit to which to add the component. """ super(HTMLComponentEditor, self).setUp(is_staff=is_staff) self.component = 'Text' self.unit = self.go_to_unit_page() self.container_page = ContainerPage(self.browser, None) self.xblock_wrapper = XBlockWrapper(self.browser, None) # Add HTML component add_component(self.container_page, 'html', self.component) self.component = self.unit.xblocks[1] self.container_page.edit() self.html_editor = HtmlXBlockEditorView(self.browser, self.component.locator) self.iframe = HTMLEditorIframe(self.browser, self.component.locator) def populate_course_fixture(self, course_fixture): """ Adds a course fixture """ course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc('vertical', 'Test Unit') ) ) ) def test_user_can_view_metadata(self): """ Scenario: User can view metadata Given I have created a Blank HTML Page And I edit and select Settings Then I see the HTML component settings """ self.html_editor.open_settings_tab() display_name_value = self.html_editor.get_default_settings()[0] display_name_key = self.html_editor.keys[0] self.assertEqual( ['Display Name', 'Text'], [display_name_key, display_name_value], "Settings not found" ) editor_value = self.html_editor.get_default_settings()[1] editor_key = self.html_editor.keys[1] self.assertEqual( ['Editor', 'Visual'], [editor_key, editor_value], "Settings not found" ) def test_user_can_modify_display_name(self): """ Scenario: User can modify display name Given I have created a Blank HTML Page And I edit and select Settings Then I can modify the display name And my display name change is persisted on save """ self.html_editor.open_settings_tab() self.html_editor.set_field_val('Display Name', 'New Name') self.html_editor.save_settings() component_name = self.unit.xblock_titles[0] self.assertEqual(component_name, 'New Name', "Component name is not as edited") def test_link_plugin_sets_url_correctly(self): """ Scenario: TinyMCE link plugin sets urls correctly Given I have created a Blank HTML Page When I edit the page And I add a link with static link "/static/image.jpg" via the Link Plugin Icon Then the href link is rewritten to the asset link "image.jpg" And the link is shown as "/static/image.jpg" in the Link Plugin """ static_link = '/static/image.jpg' self.html_editor.open_link_plugin() self.html_editor.save_static_link(static_link) self.html_editor.switch_to_iframe() href = self.iframe.href self.assertIn('image.jpg', href) self.iframe.select_link() self.iframe.switch_to_default() self.assertEqual( self.html_editor.url_from_the_link_plugin, static_link, "URL in the link plugin is different" )
class ProblemComponentEditor(ContainerBase): """ Feature: CMS.Component Adding As a course author, I want to be able to add and edit Problem """ def setUp(self, is_staff=True): """ Create a course with a section, subsection, and unit to which to add the component. """ super(ProblemComponentEditor, self).setUp(is_staff=is_staff) self.component = 'Blank Common Problem' self.unit = self.go_to_unit_page() self.container_page = ContainerPage(self.browser, None) # Add a Problem add_component(self.container_page, 'problem', self.component) self.component = self.unit.xblocks[1] self.container_page.edit() self.problem_editor = ProblemXBlockEditorView(self.browser, self.component.locator) def populate_course_fixture(self, course_fixture): """ Adds a course fixture """ course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc( 'vertical', 'Test Unit')))) def test_user_can_modify_float_input(self): """ Scenario: User can modify float input values Given I have created a Blank Common Problem When I edit and select Settings Then I can set the weight to "3.5" And my change to weight is persisted And I can revert to the default value of unset for weight """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Problem Weight', '3.5') self.problem_editor.save() # reopen settings self.container_page.edit() self.problem_editor.open_settings() field_value = self.problem_editor.get_field_val('Problem Weight') self.assertEqual(field_value, '3.5') self.problem_editor.revert_setting() field_value = self.problem_editor.get_field_val('Problem Weight') self.assertEqual(field_value, '', 'Component settings is not reverted to default') @skip_if_browser('firefox') # Lettuce tests run on chrome and chrome does not allow to enter # periods/dots in this field and consequently we have to save the # value as '234'. Whereas, bokchoy runs with the older version of # firefox on jenkins, which does not allow to save the value if it # has a period/dot. Clicking on save button after filling '2.34' in # field, does not do anything and test does not go any further. # So, it fails always. def test_user_cannot_type_decimal_values(self): """ Scenario: User cannot type decimal values integer number field Given I have created a Blank Common Problem When I edit and select Settings Then if I set the max attempts to "2.34", it will persist as a valid integer """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Maximum Attempts', '2.34') self.problem_editor.save() # reopen settings self.container_page.edit() self.problem_editor.open_settings() field_value = self.problem_editor.get_field_val('Maximum Attempts') self.assertEqual(field_value, '234', "Decimal values are not allowed in this field") def test_settings_are_not_saved_on_cancel(self): """ Scenario: Settings changes are not saved on Cancel Given I have created a Blank Common Problem When I edit and select Settings Then I can set the weight to "3.5" And I can modify the display name Then If I press Cancel my changes are not persisted """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Problem Weight', '3.5') self.problem_editor.cancel() # reopen settings self.container_page.edit() self.problem_editor.open_settings() field_value = self.problem_editor.get_field_val('Problem Weight') self.assertEqual( field_value, '', "Component setting should not appear updated if cancelled during editing" ) def test_cheat_sheet_visible_on_toggle(self): """ Scenario: Cheat sheet visible on toggle Given I have created a Blank Common Problem And I can edit the problem Then I can see cheatsheet """ self.problem_editor.toggle_cheatsheet() self.assertTrue(self.problem_editor.is_cheatsheet_present(), "Cheatsheet not present")
class ProblemComponentEditor(ContainerBase): """ Feature: CMS.Component Adding As a course author, I want to be able to add and edit Problem """ def setUp(self, is_staff=True): """ Create a course with a section, subsection, and unit to which to add the component. """ super(ProblemComponentEditor, self).setUp(is_staff=is_staff) self.component = 'Blank Common Problem' self.unit = self.go_to_unit_page() self.container_page = ContainerPage(self.browser, None) # Add a Problem add_component(self.container_page, 'problem', self.component) self.component = self.unit.xblocks[1] self.container_page.edit() self.problem_editor = ProblemXBlockEditorView(self.browser, self.component.locator) def populate_course_fixture(self, course_fixture): """ Adds a course fixture """ course_fixture.add_children( XBlockFixtureDesc('chapter', 'Test Section').add_children( XBlockFixtureDesc('sequential', 'Test Subsection').add_children( XBlockFixtureDesc( 'vertical', 'Test Unit')))) def test_user_can_view_metadata(self): """ Scenario: User can view metadata Given I have created a Blank Common Problem When I edit and select Settings Then I see the advanced settings and their expected values And Edit High Level Source is not visible """ expected_default_settings = { 'Display Name': u'Blank Common Problem', 'Matlab API key': u'', 'Maximum Attempts': u'', 'Problem Weight': u'', 'Randomization': u'Never', 'Show Answer': u'Finished', 'Show Reset Button': u'False', 'Timer Between Attempts': u'0' } self.problem_editor.open_settings() settings = self.problem_editor.get_settings() self.assertEqual(expected_default_settings, settings) self.assertFalse(self.problem_editor.is_latex_compiler_present()) def test_user_can_modify_string_values(self): """ Given I have created a Blank Common Problem When I edit and select Settings Then I can modify the display name And my display name change is persisted on save """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Display Name', 'New Name') self.problem_editor.save() component_name = self.unit.xblock_titles[0] self.assertEqual(component_name, 'New Name') def test_user_can_specify_special_characters(self): """ Scenario: User can specify special characters in String values Given I have created a Blank Common Problem When I edit and select Settings Then I can specify special characters in the display name And my special characters are persisted on save """ self.problem_editor.open_settings() self.problem_editor.set_field_val('Display Name', '&&&') self.problem_editor.save() component_name = self.unit.xblock_titles[0] self.assertEqual(component_name, '&&&')