Re-enable the component acceptance tests
This commit is contained in:
@@ -168,6 +168,18 @@ def log_into_studio(
|
||||
assert_in(uname, world.css_text('h2.title', timeout=10))
|
||||
|
||||
|
||||
def add_course_author(user, course):
|
||||
"""
|
||||
Add the user to the instructor group of the course
|
||||
so they will have the permissions to see it in studio
|
||||
"""
|
||||
for role in ("staff", "instructor"):
|
||||
groupname = get_course_groupname_for_role(course.location, role)
|
||||
group, __ = Group.objects.get_or_create(name=groupname)
|
||||
user.groups.add(group)
|
||||
user.save()
|
||||
|
||||
|
||||
def create_a_course():
|
||||
course = world.CourseFactory.create(org='MITx', course='999', display_name='Robot Super Course')
|
||||
world.scenario_dict['COURSE'] = course
|
||||
@@ -176,13 +188,7 @@ def create_a_course():
|
||||
if not user:
|
||||
user = get_user_by_email('robot+studio@edx.org')
|
||||
|
||||
# Add the user to the instructor group of the course
|
||||
# so they will have the permissions to see it in studio
|
||||
for role in ("staff", "instructor"):
|
||||
groupname = get_course_groupname_for_role(course.location, role)
|
||||
group, __ = Group.objects.get_or_create(name=groupname)
|
||||
user.groups.add(group)
|
||||
user.save()
|
||||
add_course_author(user, course)
|
||||
|
||||
# Navigate to the studio dashboard
|
||||
world.visit('/')
|
||||
|
||||
@@ -2,85 +2,87 @@
|
||||
Feature: CMS.Component Adding
|
||||
As a course author, I want to be able to add a wide variety of components
|
||||
|
||||
#Scenario: I can add components
|
||||
# Given I have opened a new course in studio
|
||||
# And I am editing a new unit
|
||||
# When I add the following components:
|
||||
# | Component |
|
||||
# | Discussion |
|
||||
# | Blank HTML |
|
||||
# | LaTex |
|
||||
# | Blank Problem|
|
||||
# | Dropdown |
|
||||
# | Multi Choice |
|
||||
# | Numerical |
|
||||
# | Text Input |
|
||||
# | Advanced |
|
||||
# | Circuit |
|
||||
# | Custom Python|
|
||||
# | Image Mapped |
|
||||
# | Math Input |
|
||||
# | Problem LaTex|
|
||||
# | Adaptive Hint|
|
||||
# | Video |
|
||||
# Then I see the following components:
|
||||
# | Component |
|
||||
# | Discussion |
|
||||
# | Blank HTML |
|
||||
# | LaTex |
|
||||
# | Blank Problem|
|
||||
# | Dropdown |
|
||||
# | Multi Choice |
|
||||
# | Numerical |
|
||||
# | Text Input |
|
||||
# | Advanced |
|
||||
# | Circuit |
|
||||
# | Custom Python|
|
||||
# | Image Mapped |
|
||||
# | Math Input |
|
||||
# | Problem LaTex|
|
||||
# | Adaptive Hint|
|
||||
# | Video |
|
||||
Scenario: I can add single step components
|
||||
Given I am in Studio editing a new unit
|
||||
When I add this type of single step component:
|
||||
| Component |
|
||||
| Discussion |
|
||||
| Video |
|
||||
Then I see this type of single step component:
|
||||
| Component |
|
||||
| Discussion |
|
||||
| Video |
|
||||
|
||||
#Scenario: I can delete Components
|
||||
# Given I have opened a new course in studio
|
||||
# And I am editing a new unit
|
||||
# And I add the following components:
|
||||
# | Component |
|
||||
# | Discussion |
|
||||
# | Blank HTML |
|
||||
# | LaTex |
|
||||
# | Blank Problem|
|
||||
# | Dropdown |
|
||||
# | Multi Choice |
|
||||
# | Numerical |
|
||||
# | Text Input |
|
||||
# | Advanced |
|
||||
# | Circuit |
|
||||
# | Custom Python|
|
||||
# | Image Mapped |
|
||||
# | Math Input |
|
||||
# | Problem LaTex|
|
||||
# | Adaptive Hint|
|
||||
# | Video |
|
||||
# When I will confirm all alerts
|
||||
# And I delete all components
|
||||
# Then I see no components
|
||||
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 |
|
||||
| E-text Written in LaTeX |
|
||||
Then I see HTML components in this order:
|
||||
| Component |
|
||||
| Text |
|
||||
| Announcement |
|
||||
| E-text Written in LaTeX |
|
||||
|
||||
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 |
|
||||
| Dropdown |
|
||||
| Multiple Choice |
|
||||
| Numerical Input |
|
||||
| Text Input |
|
||||
Then I see Problem components in this order:
|
||||
| Component |
|
||||
| Blank Common Problem |
|
||||
| Dropdown |
|
||||
| Multiple Choice |
|
||||
| Numerical Input |
|
||||
| Text Input |
|
||||
|
||||
Scenario: I can add Advanced Problem components
|
||||
Given I am in Studio editing a new unit
|
||||
When I add this type of Advanced Problem component:
|
||||
| Component |
|
||||
| Blank Advanced Problem |
|
||||
| Circuit Schematic Builder |
|
||||
| Custom Python-Evaluated Input |
|
||||
| Drag and Drop |
|
||||
| Image Mapped Input |
|
||||
| Math Expression Input |
|
||||
| Problem Written in LaTeX |
|
||||
| Problem with Adaptive Hint |
|
||||
Then I see Problem components in this order:
|
||||
| Component |
|
||||
| Blank Advanced Problem |
|
||||
| Circuit Schematic Builder |
|
||||
| Custom Python-Evaluated Input |
|
||||
| Drag and Drop |
|
||||
| Image Mapped Input |
|
||||
| Math Expression Input |
|
||||
| Problem Written in LaTeX |
|
||||
| Problem with Adaptive Hint |
|
||||
|
||||
Scenario: I see a prompt on delete
|
||||
Given I have opened a new course in studio
|
||||
And I am editing a new unit
|
||||
And I add the following components:
|
||||
| Component |
|
||||
| Discussion |
|
||||
And I delete a component
|
||||
Then I am shown a prompt
|
||||
Given I am in Studio editing a new unit
|
||||
And I add a "Discussion" "single step" component
|
||||
And I delete a component
|
||||
Then I am shown a prompt
|
||||
|
||||
Scenario: I see a notification on save
|
||||
Given I have opened a new course in studio
|
||||
And I am editing a new unit
|
||||
And I add the following components:
|
||||
| Component |
|
||||
| Discussion |
|
||||
Scenario: I can delete Components
|
||||
Given I am in Studio editing a new unit
|
||||
And I add a "Discussion" "single step" component
|
||||
And I add a "Text" "HTML" component
|
||||
And I add a "Blank Common Problem" "Problem" component
|
||||
And I add a "Blank Advanced Problem" "Advanced Problem" component
|
||||
And I delete all components
|
||||
Then I see no components
|
||||
|
||||
Scenario: I see a notification on save
|
||||
Given I am in Studio editing a new unit
|
||||
And I add a "Discussion" "single step" component
|
||||
And I edit and save a component
|
||||
Then I am shown a notification
|
||||
|
||||
@@ -2,38 +2,135 @@
|
||||
#pylint: disable=W0621
|
||||
|
||||
from lettuce import world, step
|
||||
from nose.tools import assert_true # pylint: disable=E0611
|
||||
|
||||
DATA_LOCATION = 'i4x://edx/templates'
|
||||
from nose.tools import assert_true, assert_in, assert_equal # pylint: disable=E0611
|
||||
from common import create_studio_user, add_course_author, log_into_studio
|
||||
|
||||
|
||||
@step(u'I am editing a new unit')
|
||||
@step(u'I am in Studio editing a new unit$')
|
||||
def add_unit(step):
|
||||
css_selectors = ['a.new-courseware-section-button', 'input.new-section-name-save', 'a.new-subsection-item',
|
||||
'input.new-subsection-name-save', 'div.section-item a.expand-collapse-icon', 'a.new-unit-item']
|
||||
world.clear_courses()
|
||||
course = world.CourseFactory.create()
|
||||
section = world.ItemFactory.create(parent_location=course.location)
|
||||
world.ItemFactory.create(
|
||||
parent_location=section.location,
|
||||
category='sequential',
|
||||
display_name='Subsection One',)
|
||||
user = create_studio_user(is_staff=False)
|
||||
add_course_author(user, course)
|
||||
log_into_studio()
|
||||
css_selectors = ['a.course-link', 'div.section-item a.expand-collapse-icon', 'a.new-unit-item']
|
||||
for selector in css_selectors:
|
||||
world.css_click(selector)
|
||||
|
||||
|
||||
@step(u'I add the following components:')
|
||||
def add_components(step):
|
||||
for component in [step_hash['Component'] for step_hash in step.hashes]:
|
||||
assert component in COMPONENT_DICTIONARY
|
||||
for css in COMPONENT_DICTIONARY[component]['steps']:
|
||||
world.css_click(css)
|
||||
@step(u'I add this type of single step component:$')
|
||||
def add_a_single_step_component(step):
|
||||
for step_hash in step.hashes:
|
||||
component = step_hash['Component']
|
||||
assert_in(component, ['Discussion', 'Video'])
|
||||
css_selector = 'a[data-type="{}"]'.format(component.lower())
|
||||
world.css_click(css_selector)
|
||||
|
||||
|
||||
@step(u'I see the following components')
|
||||
def check_components(step):
|
||||
for component in [step_hash['Component'] for step_hash in step.hashes]:
|
||||
assert component in COMPONENT_DICTIONARY
|
||||
assert_true(COMPONENT_DICTIONARY[component]['found_func'](), "{} couldn't be found".format(component))
|
||||
@step(u'I see this type of single step component:$')
|
||||
def see_a_single_step_component(step):
|
||||
for step_hash in step.hashes:
|
||||
component = step_hash['Component']
|
||||
assert_in(component, ['Discussion', 'Video'])
|
||||
component_css = 'section.xmodule_{}Module'.format(component)
|
||||
assert_true(world.is_css_present(component_css),
|
||||
"{} couldn't be found".format(component))
|
||||
|
||||
|
||||
@step(u'I delete all components')
|
||||
@step(u'I add this type of( Advanced)? (HTML|Problem) component:$')
|
||||
def add_a_multi_step_component(step, is_advanced, category):
|
||||
def click_advanced():
|
||||
css = 'ul.problem-type-tabs a[href="#tab2"]'
|
||||
world.css_click(css)
|
||||
my_css = 'ul.problem-type-tabs li.ui-state-active a[href="#tab2"]'
|
||||
assert(world.css_find(my_css))
|
||||
|
||||
def find_matching_link():
|
||||
"""
|
||||
Find the link with the specified text. There should be one and only one.
|
||||
"""
|
||||
# The tab shows links for the given category
|
||||
links = world.css_find('div.new-component-{} a'.format(category))
|
||||
|
||||
# Find the link whose text matches what you're looking for
|
||||
matched_links = [link for link in links if link.text == step_hash['Component']]
|
||||
|
||||
# There should be one and only one
|
||||
assert_equal(len(matched_links), 1)
|
||||
return matched_links[0]
|
||||
|
||||
def click_link():
|
||||
link.click()
|
||||
|
||||
category = category.lower()
|
||||
for step_hash in step.hashes:
|
||||
css_selector = 'a[data-type="{}"]'.format(category)
|
||||
world.css_click(css_selector)
|
||||
world.wait_for_invisible(css_selector)
|
||||
|
||||
if is_advanced:
|
||||
# Sometimes this click does not work if you go too fast.
|
||||
world.retry_on_exception(click_advanced, max_attempts=5, ignored_exceptions=AssertionError)
|
||||
|
||||
# Retry this in case the list is empty because you tried too fast.
|
||||
link = world.retry_on_exception(func=find_matching_link, ignored_exceptions=AssertionError)
|
||||
|
||||
# Wait for the link to be clickable. If you go too fast it is not.
|
||||
world.retry_on_exception(click_link)
|
||||
|
||||
|
||||
@step(u'I see (HTML|Problem) components in this order:')
|
||||
def see_a_multi_step_component(step, category):
|
||||
components = world.css_find('li.component section.xmodule_display')
|
||||
for idx, step_hash in enumerate(step.hashes):
|
||||
if category == 'HTML':
|
||||
html_matcher = {
|
||||
'Text':
|
||||
'\n \n',
|
||||
'Announcement':
|
||||
'<p> Words of encouragement! This is a short note that most students will read. </p>',
|
||||
'E-text Written in LaTeX':
|
||||
'<h2>Example: E-text page</h2>',
|
||||
}
|
||||
assert_in(html_matcher[step_hash['Component']], components[idx].html)
|
||||
else:
|
||||
assert_in(step_hash['Component'].upper(), components[idx].text)
|
||||
|
||||
|
||||
@step(u'I add a "([^"]*)" "([^"]*)" component$')
|
||||
def add_component_catetory(step, component, category):
|
||||
assert category in ('single step', 'HTML', 'Problem', 'Advanced Problem')
|
||||
given_string = 'I add this type of {} component:'.format(category)
|
||||
step.given('{}\n{}\n{}'.format(given_string, '|Component|', '|{}|'.format(component)))
|
||||
|
||||
|
||||
@step(u'I delete all components$')
|
||||
def delete_all_components(step):
|
||||
for _ in range(len(COMPONENT_DICTIONARY)):
|
||||
world.css_click('a.delete-button')
|
||||
delete_btn_css = 'a.delete-button'
|
||||
prompt_css = 'div#prompt-warning'
|
||||
btn_css = '{} a.button.action-primary'.format(prompt_css)
|
||||
saving_mini_css = 'div#page-notification .wrapper-notification-mini'
|
||||
count = len(world.css_find('ol.components li.component'))
|
||||
for _ in range(int(count)):
|
||||
world.css_click(delete_btn_css)
|
||||
assert_true(world.is_css_present('{}.is-shown'.format(prompt_css)),
|
||||
msg='Waiting for the confirmation prompt to be shown')
|
||||
|
||||
# Pressing the button via css was not working reliably for the last component
|
||||
# when run in Chrome.
|
||||
if world.browser.driver_name is 'Chrome':
|
||||
world.browser.execute_script("$('{}').click()".format(btn_css))
|
||||
else:
|
||||
world.css_click(btn_css)
|
||||
|
||||
# Wait for the saving notification to pop up then disappear
|
||||
if world.is_css_present('{}.is-shown'.format(saving_mini_css)):
|
||||
world.css_find('{}.is-hiding'.format(saving_mini_css))
|
||||
|
||||
|
||||
@step(u'I see no components')
|
||||
@@ -50,88 +147,3 @@ def delete_one_component(step):
|
||||
def edit_and_save_component(step):
|
||||
world.css_click('.edit-button')
|
||||
world.css_click('.save-button')
|
||||
|
||||
|
||||
def step_selector_list(data_type, path, index=1):
|
||||
selector_list = ['a[data-type="{}"]'.format(data_type)]
|
||||
if index != 1:
|
||||
selector_list.append('a[id="ui-id-{}"]'.format(index))
|
||||
if path is not None:
|
||||
selector_list.append('a[data-location="{}/{}/{}"]'.format(DATA_LOCATION, data_type, path))
|
||||
return selector_list
|
||||
|
||||
|
||||
def found_text_func(text):
|
||||
return lambda: world.browser.is_text_present(text)
|
||||
|
||||
|
||||
def found_css_func(css):
|
||||
return lambda: world.is_css_present(css, wait_time=2)
|
||||
|
||||
COMPONENT_DICTIONARY = {
|
||||
'Discussion': {
|
||||
'steps': step_selector_list('discussion', None),
|
||||
'found_func': found_css_func('section.xmodule_DiscussionModule')
|
||||
},
|
||||
'Blank HTML': {
|
||||
'steps': step_selector_list('html', 'Blank_HTML_Page'),
|
||||
#this one is a blank html so a more refined search is being done
|
||||
'found_func': lambda: '\n \n' in [x.html for x in world.css_find('section.xmodule_HtmlModule')]
|
||||
},
|
||||
'LaTex': {
|
||||
'steps': step_selector_list('html', 'E-text_Written_in_LaTeX'),
|
||||
'found_func': found_text_func('EXAMPLE: E-TEXT PAGE')
|
||||
},
|
||||
'Blank Problem': {
|
||||
'steps': step_selector_list('problem', 'Blank_Common_Problem'),
|
||||
'found_func': found_text_func('BLANK COMMON PROBLEM')
|
||||
},
|
||||
'Dropdown': {
|
||||
'steps': step_selector_list('problem', 'Dropdown'),
|
||||
'found_func': found_text_func('DROPDOWN')
|
||||
},
|
||||
'Multi Choice': {
|
||||
'steps': step_selector_list('problem', 'Multiple_Choice'),
|
||||
'found_func': found_text_func('MULTIPLE CHOICE')
|
||||
},
|
||||
'Numerical': {
|
||||
'steps': step_selector_list('problem', 'Numerical_Input'),
|
||||
'found_func': found_text_func('NUMERICAL INPUT')
|
||||
},
|
||||
'Text Input': {
|
||||
'steps': step_selector_list('problem', 'Text_Input'),
|
||||
'found_func': found_text_func('TEXT INPUT')
|
||||
},
|
||||
'Advanced': {
|
||||
'steps': step_selector_list('problem', 'Blank_Advanced_Problem', index=2),
|
||||
'found_func': found_text_func('BLANK ADVANCED PROBLEM')
|
||||
},
|
||||
'Circuit': {
|
||||
'steps': step_selector_list('problem', 'Circuit_Schematic_Builder', index=2),
|
||||
'found_func': found_text_func('CIRCUIT SCHEMATIC BUILDER')
|
||||
},
|
||||
'Custom Python': {
|
||||
'steps': step_selector_list('problem', 'Custom_Python-Evaluated_Input', index=2),
|
||||
'found_func': found_text_func('CUSTOM PYTHON-EVALUATED INPUT')
|
||||
},
|
||||
'Image Mapped': {
|
||||
'steps': step_selector_list('problem', 'Image_Mapped_Input', index=2),
|
||||
'found_func': found_text_func('IMAGE MAPPED INPUT')
|
||||
},
|
||||
'Math Input': {
|
||||
'steps': step_selector_list('problem', 'Math_Expression_Input', index=2),
|
||||
'found_func': found_text_func('MATH EXPRESSION INPUT')
|
||||
},
|
||||
'Problem LaTex': {
|
||||
'steps': step_selector_list('problem', 'Problem_Written_in_LaTeX', index=2),
|
||||
'found_func': found_text_func('PROBLEM WRITTEN IN LATEX')
|
||||
},
|
||||
'Adaptive Hint': {
|
||||
'steps': step_selector_list('problem', 'Problem_with_Adaptive_Hint', index=2),
|
||||
'found_func': found_text_func('PROBLEM WITH ADAPTIVE HINT')
|
||||
},
|
||||
'Video': {
|
||||
'steps': step_selector_list('video', None),
|
||||
'found_func': found_css_func('section.xmodule_VideoModule')
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user