Selenium tests.
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
#pylint: disable=C0111
|
||||
#pylint: disable=W0621
|
||||
|
||||
from lettuce import world
|
||||
from nose.tools import assert_equal
|
||||
from terrain.steps import reload_the_page
|
||||
|
||||
import time
|
||||
|
||||
@world.absorb
|
||||
def create_component_instance(step, component_button_css, instance_id, expected_css):
|
||||
click_new_component_button(step, component_button_css)
|
||||
click_component_from_menu(instance_id, expected_css)
|
||||
|
||||
@world.absorb
|
||||
def click_new_component_button(step, component_button_css):
|
||||
step.given('I have opened a new course section in Studio')
|
||||
step.given('I have added a new subsection')
|
||||
step.given('I expand the first section')
|
||||
world.css_click('a.new-unit-item')
|
||||
world.css_click(component_button_css)
|
||||
|
||||
@world.absorb
|
||||
def click_component_from_menu(instance_id, expected_css):
|
||||
new_instance = world.browser.find_by_id(instance_id)
|
||||
assert_equal(1, len(new_instance))
|
||||
# TODO: why is this sleep necessary?
|
||||
time.sleep(float(1))
|
||||
new_instance[0].click()
|
||||
assert_equal(1, len(world.css_find(expected_css)))
|
||||
|
||||
@world.absorb
|
||||
def edit_component_and_select_settings():
|
||||
world.css_click('a.edit-button')
|
||||
world.css_click('#settings-mode')
|
||||
|
||||
@world.absorb
|
||||
def verify_setting_entry(setting, display_name, value, explicitly_set):
|
||||
assert_equal(display_name, setting.find_by_css('.setting-label')[0].value)
|
||||
assert_equal(value, setting.find_by_css('.setting-input')[0].value)
|
||||
settingClearButton = setting.find_by_css('.setting-clear')[0]
|
||||
assert_equal(explicitly_set, settingClearButton.has_class('active'))
|
||||
assert_equal(not explicitly_set, settingClearButton.has_class('inactive'))
|
||||
|
||||
@world.absorb
|
||||
def verify_all_setting_entries(expected_entries):
|
||||
settings = world.browser.find_by_css('.wrapper-comp-setting')
|
||||
assert_equal(len(expected_entries), len(settings))
|
||||
for (counter, setting) in enumerate(settings):
|
||||
world.verify_setting_entry(setting, expected_entries[counter][0],
|
||||
expected_entries[counter][1], expected_entries[counter][2])
|
||||
|
||||
@world.absorb
|
||||
def save_component_and_reopen(step):
|
||||
world.css_click("a.save-button")
|
||||
# We have a known issue that modifications are still shown within the edit window after cancel (though)
|
||||
# they are not persisted. Refresh the browser to make sure the changes WERE persisted after Save.
|
||||
reload_the_page(step)
|
||||
edit_component_and_select_settings()
|
||||
|
||||
@world.absorb
|
||||
def cancel_component(step):
|
||||
world.css_click("a.cancel-button")
|
||||
# We have a known issue that modifications are still shown within the edit window after cancel (though)
|
||||
# they are not persisted. Refresh the browser to make sure the changes were not persisted.
|
||||
reload_the_page(step)
|
||||
|
||||
@world.absorb
|
||||
def revert_setting_entry(label):
|
||||
get_setting_entry(label).find_by_css('.setting-clear')[0].click()
|
||||
|
||||
@world.absorb
|
||||
def get_setting_entry(label):
|
||||
settings = world.browser.find_by_css('.wrapper-comp-setting')
|
||||
for setting in settings:
|
||||
if setting.find_by_css('.setting-label')[0].value == label:
|
||||
return setting
|
||||
return None
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
Feature: Discussion Component Editor
|
||||
As a course author, I want to be able to create discussion components.
|
||||
|
||||
Scenario: User can view metadata
|
||||
Given I have created a Discussion Tag
|
||||
And I edit and select Settings
|
||||
Then I see three alphabetized settings and their expected values
|
||||
|
||||
Scenario: User can modify display name
|
||||
Given I have created a Discussion Tag
|
||||
And I edit and select Settings
|
||||
Then I can modify the display name
|
||||
And my display name change is persisted on save
|
||||
18
cms/djangoapps/contentstore/features/discussion-editor.py
Normal file
18
cms/djangoapps/contentstore/features/discussion-editor.py
Normal file
@@ -0,0 +1,18 @@
|
||||
#pylint: disable=C0111
|
||||
#pylint: disable=W0621
|
||||
|
||||
from lettuce import world, step
|
||||
|
||||
@step('I have created a Discussion Tag$')
|
||||
def i_created_blank_common_problem(step):
|
||||
world.create_component_instance(step, '.large-discussion-icon', 'i4x://edx/templates/discussion/Discussion_Tag',
|
||||
'.xmodule_DiscussionModule')
|
||||
|
||||
@step('I see three alphabetized settings and their expected values$')
|
||||
def i_see_only_the_display_name(step):
|
||||
world.verify_all_setting_entries(
|
||||
[
|
||||
['Category', "Week 1", True],
|
||||
['Display Name', "Discussion Tag", True],
|
||||
['Subcategory', "Topic-Level Student-Visible Label", True]
|
||||
])
|
||||
13
cms/djangoapps/contentstore/features/html-editor.feature
Normal file
13
cms/djangoapps/contentstore/features/html-editor.feature
Normal file
@@ -0,0 +1,13 @@
|
||||
Feature: HTML Editor
|
||||
As a course author, I want to be able to create HTML blocks.
|
||||
|
||||
Scenario: User can view metadata
|
||||
Given I have created a Blank HTML Page
|
||||
And I edit and select Settings
|
||||
Then I see only the HTML display name setting
|
||||
|
||||
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
|
||||
13
cms/djangoapps/contentstore/features/html-editor.py
Normal file
13
cms/djangoapps/contentstore/features/html-editor.py
Normal file
@@ -0,0 +1,13 @@
|
||||
#pylint: disable=C0111
|
||||
#pylint: disable=W0621
|
||||
|
||||
from lettuce import world, step
|
||||
|
||||
@step('I have created a Blank HTML Page$')
|
||||
def i_created_blank_common_problem(step):
|
||||
world.create_component_instance(step, '.large-html-icon', 'i4x://edx/templates/html/Blank_HTML_Page',
|
||||
'.xmodule_HtmlModule')
|
||||
|
||||
@step('I see only the HTML display name setting$')
|
||||
def i_see_only_the_html_display_name(step):
|
||||
world.verify_all_setting_entries([['Display Name', "Blank HTML Page", True]])
|
||||
@@ -1,5 +1,65 @@
|
||||
Feature: Problem Editor
|
||||
As a course author, I want to be able to create problems.
|
||||
As a course author, I want to be able to create problems and edit their settings.
|
||||
|
||||
Scenario: User can view metadata
|
||||
Given I have created a Blank Common Problem
|
||||
Given I have created a Blank Common Problem
|
||||
And I edit and select Settings
|
||||
Then I see five alphabetized settings and their expected values
|
||||
And Edit High Level Source is not visible
|
||||
|
||||
Scenario: User can modify String values
|
||||
Given I have created a Blank Common Problem
|
||||
And I edit and select Settings
|
||||
Then I can modify the display name
|
||||
And my display name change is persisted on save
|
||||
|
||||
Scenario: User can revert display name to unset
|
||||
Given I have created a Blank Common Problem
|
||||
And I edit and select Settings
|
||||
Then I can revert the display name to unset
|
||||
And my display name is unset on save
|
||||
|
||||
Scenario: User can select values in a Select
|
||||
Given I have created a Blank Common Problem
|
||||
And 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
|
||||
|
||||
Scenario: User can modify float input values
|
||||
Given I have created a Blank Common Problem
|
||||
And 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
|
||||
|
||||
Scenario: User cannot type letters in float number field
|
||||
Given I have created a Blank Common Problem
|
||||
And I edit and select Settings
|
||||
Then if I set the weight to abc, it remains unset
|
||||
|
||||
Scenario: User cannot type decimal values integer number field
|
||||
Given I have created a Blank Common Problem
|
||||
And I edit and select Settings
|
||||
Then if I set the max attempts to 2.34, the max attempts are persisted as 234
|
||||
|
||||
Scenario: User cannot type out of range values in an integer number field
|
||||
Given I have created a Blank Common Problem
|
||||
And I edit and select Settings
|
||||
Then if I set the max attempts to -3, the max attempts are persisted as 1
|
||||
|
||||
|
||||
Scenario: Settings changes are not saved on Cancel
|
||||
Given I have created a Blank Common Problem
|
||||
And 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
|
||||
|
||||
Scenario: Edit High Level source is available for LaTeX problem
|
||||
Given I have created a LaTeX Problem
|
||||
And I edit and select Settings
|
||||
Then Edit High Level Source is visible
|
||||
|
||||
# Future tests to add--
|
||||
# Check that code is shown in editor (type code, Save, check that code appears when re-edited).
|
||||
|
||||
@@ -2,16 +2,146 @@
|
||||
#pylint: disable=W0621
|
||||
|
||||
from lettuce import world, step
|
||||
from nose.tools import assert_true, assert_equal, assert_in
|
||||
from terrain.steps import reload_the_page
|
||||
from nose.tools import assert_equal
|
||||
|
||||
DISPLAY_NAME = "Display Name"
|
||||
MAXIMUM_ATTEMPTS="Maximum Attempts"
|
||||
PROBLEM_WEIGHT="Problem Weight"
|
||||
RANDOMIZATION='Randomization'
|
||||
SHOW_ANSWER="Show Answer"
|
||||
|
||||
############### ACTIONS ####################
|
||||
@step('I have created a Blank Common Problem$')
|
||||
def i_created_blank_common_problem(step):
|
||||
step.given('I have opened a new course section in Studio')
|
||||
step.given('I have added a new subsection')
|
||||
step.given('I expand the first section')
|
||||
world.css_click('a.new-unit-item')
|
||||
world.css_click('.large-problem-icon')
|
||||
world.css_click('#i4x://edx/templates/problem/Blank_Common_Problem')
|
||||
world.create_component_instance(step, '.large-problem-icon', 'i4x://edx/templates/problem/Blank_Common_Problem',
|
||||
'.xmodule_CapaModule')
|
||||
|
||||
@step('I edit and select Settings$')
|
||||
def i_edit_and_select_settings(step):
|
||||
world.edit_component_and_select_settings()
|
||||
|
||||
@step('I see five alphabetized settings and their expected values$')
|
||||
def i_see_five_settings_with_values(step):
|
||||
world.verify_all_setting_entries(
|
||||
[
|
||||
[DISPLAY_NAME, "Blank Common Problem", True],
|
||||
[MAXIMUM_ATTEMPTS, "", False],
|
||||
[PROBLEM_WEIGHT, "", False],
|
||||
[RANDOMIZATION, "Never", True],
|
||||
[SHOW_ANSWER, "Finished", True]
|
||||
])
|
||||
|
||||
@step('I can modify the display name')
|
||||
def i_can_modify_the_display_name(step):
|
||||
world.get_setting_entry(DISPLAY_NAME).find_by_css('.setting-input')[0].fill('modified')
|
||||
verify_modified_display_name()
|
||||
|
||||
@step('my display name change is persisted on save')
|
||||
def my_display_name_change_is_persisted_on_save(step):
|
||||
world.save_component_and_reopen(step)
|
||||
verify_modified_display_name()
|
||||
|
||||
@step('I can revert the display name to unset')
|
||||
def can_revert_display_name_to_unset(step):
|
||||
world.revert_setting_entry(DISPLAY_NAME)
|
||||
verify_unset_display_name()
|
||||
|
||||
@step('my display name is unset on save')
|
||||
def my_display_name_is_persisted_on_save(step):
|
||||
world.save_component_and_reopen(step)
|
||||
verify_unset_display_name()
|
||||
|
||||
@step('I can select Per Student for Randomization')
|
||||
def i_can_select_per_student_for_randomization(step):
|
||||
world.browser.select(RANDOMIZATION, "Per Student")
|
||||
verify_modified_randomization()
|
||||
|
||||
@step('my change to randomization is persisted')
|
||||
def my_change_to_randomization_is_persisted(step):
|
||||
world.save_component_and_reopen(step)
|
||||
verify_modified_randomization()
|
||||
|
||||
@step('I can revert to the default value for randomization')
|
||||
def i_can_revert_to_default_for_randomization(step):
|
||||
world.revert_setting_entry(RANDOMIZATION)
|
||||
world.save_component_and_reopen(step)
|
||||
world.verify_setting_entry(world.get_setting_entry(RANDOMIZATION), RANDOMIZATION, "Always", False)
|
||||
|
||||
@step('I can set the weight to 3.5')
|
||||
def i_can_set_weight_to_3_5(step):
|
||||
world.get_setting_entry(PROBLEM_WEIGHT).find_by_css('.setting-input')[0].fill('3.5')
|
||||
verify_modified_weight()
|
||||
|
||||
@step('my change to weight is persisted')
|
||||
def my_change_to_randomization_is_persisted(step):
|
||||
world.save_component_and_reopen(step)
|
||||
verify_modified_weight()
|
||||
|
||||
@step('I can revert to the default value of unset for weight')
|
||||
def i_can_revert_to_default_for_randomization(step):
|
||||
world.revert_setting_entry(PROBLEM_WEIGHT)
|
||||
world.save_component_and_reopen(step)
|
||||
world.verify_setting_entry(world.get_setting_entry(PROBLEM_WEIGHT), PROBLEM_WEIGHT, "", False)
|
||||
|
||||
@step('if I set the weight to abc, it remains unset')
|
||||
def set_the_weight_to_abc(step):
|
||||
world.get_setting_entry(PROBLEM_WEIGHT).find_by_css('.setting-input')[0].fill('abc')
|
||||
# We show the clear button immediately on type, hence the "True" here.
|
||||
world.verify_setting_entry(world.get_setting_entry(PROBLEM_WEIGHT), PROBLEM_WEIGHT, "", True)
|
||||
world.save_component_and_reopen(step)
|
||||
# But no change was actually ever sent to the model, so on reopen, explicitly_set is False
|
||||
world.verify_setting_entry(world.get_setting_entry(PROBLEM_WEIGHT), PROBLEM_WEIGHT, "", False)
|
||||
|
||||
@step('if I set the max attempts to 2.34, the max attempts are persisted as 234')
|
||||
def set_the_weight_to_abc(step):
|
||||
world.get_setting_entry(MAXIMUM_ATTEMPTS).find_by_css('.setting-input')[0].fill('2.34')
|
||||
world.verify_setting_entry(world.get_setting_entry(MAXIMUM_ATTEMPTS), MAXIMUM_ATTEMPTS, "234", True)
|
||||
world.save_component_and_reopen(step)
|
||||
world.verify_setting_entry(world.get_setting_entry(MAXIMUM_ATTEMPTS), MAXIMUM_ATTEMPTS, "234", True)
|
||||
|
||||
@step('I set the max attempts to -3, the max attempts are persisted as 1')
|
||||
def set_max_attempts_to_neg_3(step):
|
||||
world.get_setting_entry(MAXIMUM_ATTEMPTS).find_by_css('.setting-input')[0].fill('-3')
|
||||
world.verify_setting_entry(world.get_setting_entry(MAXIMUM_ATTEMPTS), MAXIMUM_ATTEMPTS, "-3", True)
|
||||
world.save_component_and_reopen(step)
|
||||
world.verify_setting_entry(world.get_setting_entry(MAXIMUM_ATTEMPTS), MAXIMUM_ATTEMPTS, "1", True)
|
||||
|
||||
@step('Edit High Level Source is not visible')
|
||||
def edit_high_level_source_not_visible(step):
|
||||
verify_high_level_source(step, False)
|
||||
|
||||
@step('Edit High Level Source is visible')
|
||||
def edit_high_level_source_visible(step):
|
||||
verify_high_level_source(step, True)
|
||||
|
||||
@step('If I press Cancel my changes are not persisted')
|
||||
def cancel_does_not_save_changes(step):
|
||||
world.cancel_component(step)
|
||||
step.given("I edit and select Settings")
|
||||
step.given("I see five alphabetized settings and their expected values")
|
||||
|
||||
@step('I have created a LaTeX Problem')
|
||||
def create_latex_problem(step):
|
||||
world.click_new_component_button(step, '.large-problem-icon')
|
||||
# Go to advanced tab (waiting for the tab to be visible)
|
||||
world.css_find('#ui-id-2')
|
||||
world.css_click('#ui-id-2')
|
||||
world.click_component_from_menu("i4x://edx/templates/problem/Problem_Written_in_LaTeX", '.xmodule_CapaModule')
|
||||
|
||||
def verify_high_level_source(step, visible):
|
||||
assert_equal(visible, world.is_css_present('.launch-latex-compiler'))
|
||||
world.cancel_component(step)
|
||||
assert_equal(visible, world.is_css_present('.upload-button'))
|
||||
|
||||
def verify_modified_weight():
|
||||
world.verify_setting_entry(world.get_setting_entry(PROBLEM_WEIGHT), PROBLEM_WEIGHT, "3.5", True)
|
||||
|
||||
def verify_modified_randomization():
|
||||
world.verify_setting_entry(world.get_setting_entry(RANDOMIZATION), RANDOMIZATION, "Per Student", True)
|
||||
|
||||
def verify_modified_display_name():
|
||||
world.verify_setting_entry(world.get_setting_entry(DISPLAY_NAME), DISPLAY_NAME, 'modified', True)
|
||||
|
||||
def verify_unset_display_name():
|
||||
world.verify_setting_entry(world.get_setting_entry(DISPLAY_NAME), DISPLAY_NAME, '', False)
|
||||
|
||||
|
||||
13
cms/djangoapps/contentstore/features/video-editor.feature
Normal file
13
cms/djangoapps/contentstore/features/video-editor.feature
Normal file
@@ -0,0 +1,13 @@
|
||||
Feature: Video Component Editor
|
||||
As a course author, I want to be able to create video components.
|
||||
|
||||
Scenario: User can view metadata
|
||||
Given I have created a Video component
|
||||
And I edit and select Settings
|
||||
Then I see only the Video display name setting
|
||||
|
||||
Scenario: User can modify display name
|
||||
Given I have created a Video component
|
||||
And I edit and select Settings
|
||||
Then I can modify the display name
|
||||
And my display name change is persisted on save
|
||||
13
cms/djangoapps/contentstore/features/video-editor.py
Normal file
13
cms/djangoapps/contentstore/features/video-editor.py
Normal file
@@ -0,0 +1,13 @@
|
||||
#pylint: disable=C0111
|
||||
#pylint: disable=W0621
|
||||
|
||||
from lettuce import world, step
|
||||
|
||||
@step('I have created a Video component$')
|
||||
def i_created_a_video_component(step):
|
||||
world.create_component_instance(step, '.large-video-icon', 'i4x://edx/templates/video/default',
|
||||
'.xmodule_VideoModule')
|
||||
|
||||
@step('I see only the video display name setting$')
|
||||
def i_see_only_the_video_display_name(step):
|
||||
world.verify_all_setting_entries([['Display Name', "default", True]])
|
||||
@@ -235,6 +235,7 @@ CMS.Views.Metadata.Number = CMS.Views.Metadata.AbstractEditor.extend({
|
||||
value = this.min;
|
||||
}
|
||||
this.setValueInEditor(value);
|
||||
this.updateModel();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user