Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
8ab2e3c3
Commit
8ab2e3c3
authored
Oct 02, 2013
by
Jay Zoldak
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1179 from edx/zoldak/enable-component-acceptance-tests
Re-enable the component acceptance tests
parents
38642d28
50dc93dc
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
212 additions
and
192 deletions
+212
-192
cms/djangoapps/contentstore/features/common.py
+13
-7
cms/djangoapps/contentstore/features/component.feature
+78
-76
cms/djangoapps/contentstore/features/component.py
+121
-109
No files found.
cms/djangoapps/contentstore/features/common.py
View file @
8ab2e3c3
...
...
@@ -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
(
'/'
)
...
...
cms/djangoapps/contentstore/features/component.feature
View file @
8ab2e3c3
...
...
@@ -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
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 have opened a new course in studio
And
I am editing a new unit
And I add the following components
:
|
Component
|
|
Discussion
|
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
cms/djangoapps/contentstore/features/component.py
View file @
8ab2e3c3
...
...
@@ -2,38 +2,135 @@
#pylint: disable=W0621
from
lettuce
import
world
,
step
from
nose.tools
import
assert_true
# pylint: disable=E0611
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
DATA_LOCATION
=
'i4x://edx/templates'
@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 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 delete all components'
)
@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 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 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'
)
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment