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
3257a7ba
Commit
3257a7ba
authored
Oct 06, 2013
by
Will Daly
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactored navigation feature
Fixed grading tests
parent
4bb9dcf1
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
127 additions
and
78 deletions
+127
-78
cms/djangoapps/contentstore/features/common.py
+9
-25
cms/djangoapps/contentstore/features/component_settings_editor_helpers.py
+9
-7
cms/djangoapps/contentstore/features/grading.py
+25
-13
cms/djangoapps/contentstore/features/video-editor.py
+20
-13
common/djangoapps/terrain/course_helpers.py
+6
-6
common/djangoapps/terrain/ui_helpers.py
+46
-3
lms/djangoapps/courseware/features/navigation.feature
+12
-11
lms/djangoapps/courseware/features/navigation.py
+0
-0
No files found.
cms/djangoapps/contentstore/features/common.py
View file @
3257a7ba
...
...
@@ -2,7 +2,7 @@
# pylint: disable=W0621
from
lettuce
import
world
,
step
from
nose.tools
import
assert_true
,
assert_in
,
assert_false
# pylint: disable=E0611
from
nose.tools
import
assert_true
,
assert_
equal
,
assert_
in
,
assert_false
# pylint: disable=E0611
from
auth.authz
import
get_user_by_email
,
get_course_groupname_for_role
from
django.conf
import
settings
...
...
@@ -64,32 +64,16 @@ def select_new_course(_step, whom):
@step
(
u'I press the "([^"]*)" notification button$'
)
def
press_the_notification_button
(
_step
,
name
):
# TODO: fix up this code. Selenium is not dealing well with css transforms,
# as it thinks that the notification and the buttons are always visible
# First wait for the notification to pop up
notification_css
=
'div#page-notification div.wrapper-notification'
world
.
wait_for_visible
(
notification_css
)
# You would think that the above would have worked, but it doesn't.
# Brute force wait for now.
world
.
wait
(
.
5
)
# Now make sure the button is there
# Because the notification uses a CSS transition,
# Selenium will always report it as being visible.
# This makes it very difficult to successfully click
# the "Save" button at the UI level.
# Instead, we use JavaScript to reliably click
# the button.
btn_css
=
'div#page-notification a.action-
%
s'
%
name
.
lower
()
world
.
wait_for_visible
(
btn_css
)
# You would think that the above would have worked, but it doesn't.
# Brute force wait for now.
world
.
wait
(
.
5
)
if
world
.
is_firefox
():
# This is done to explicitly make the changes save on firefox.
# It will remove focus from the previously focused element
world
.
trigger_event
(
btn_css
,
event
=
'focus'
)
world
.
browser
.
execute_script
(
"$('{}').click()"
.
format
(
btn_css
))
else
:
world
.
css_click
(
btn_css
)
world
.
trigger_event
(
btn_css
,
event
=
'focus'
)
world
.
browser
.
execute_script
(
"$('{}').click()"
.
format
(
btn_css
))
world
.
wait_for_ajax_complete
()
...
...
cms/djangoapps/contentstore/features/component_settings_editor_helpers.py
View file @
3257a7ba
...
...
@@ -2,7 +2,7 @@
#pylint: disable=C0111
from
lettuce
import
world
from
nose.tools
import
assert_equal
# pylint: disable=E0611
from
nose.tools
import
assert_equal
,
assert_true
# pylint: disable=E0611
from
terrain.steps
import
reload_the_page
...
...
@@ -12,9 +12,13 @@ def create_component_instance(step, component_button_css, category,
has_multiple_templates
=
True
):
click_new_component_button
(
step
,
component_button_css
)
if
category
in
(
'problem'
,
'html'
):
def
animation_done
(
_driver
):
return
world
.
browser
.
evaluate_script
(
"$('div.new-component').css('display')"
)
==
'none'
script
=
"$('div.new-component').css('display')"
return
world
.
browser
.
evaluate_script
(
script
)
==
'none'
world
.
wait_for
(
animation_done
)
if
has_multiple_templates
:
...
...
@@ -23,10 +27,7 @@ def create_component_instance(step, component_button_css, category,
if
category
in
(
'video'
,):
world
.
wait_for_xmodule
()
assert_equal
(
1
,
len
(
world
.
css_find
(
expected_css
)),
"Component instance with css {css} was not created successfully"
.
format
(
css
=
expected_css
))
assert_true
(
world
.
is_css_present
(
expected_css
))
@world.absorb
...
...
@@ -34,7 +35,8 @@ def click_new_component_button(step, component_button_css):
step
.
given
(
'I have clicked the new unit button'
)
world
.
wait_for_requirejs
(
[
"jquery"
,
"js/models/course"
,
"coffee/src/models/module"
,
"coffee/src/views/unit"
,
"jquery.ui"
])
"coffee/src/views/unit"
,
"jquery.ui"
]
)
world
.
css_click
(
component_button_css
)
...
...
cms/djangoapps/contentstore/features/grading.py
View file @
3257a7ba
...
...
@@ -6,7 +6,7 @@ from common import *
from
terrain.steps
import
reload_the_page
from
selenium.common.exceptions
import
(
InvalidElementStateException
,
WebDriverException
)
from
nose.tools
import
assert_in
,
assert_not_in
# pylint: disable=E0611
from
nose.tools
import
assert_in
,
assert_not_in
,
assert_equal
,
assert_not_equal
# pylint: disable=E0611
@step
(
u'I am viewing the grading settings'
)
...
...
@@ -36,7 +36,7 @@ def delete_grade(step):
def
view_grade_slider
(
step
,
how_many
):
grade_slider_css
=
'.grade-specific-bar'
all_grades
=
world
.
css_find
(
grade_slider_css
)
assert
len
(
all_grades
)
==
int
(
how_many
)
assert
_equal
(
len
(
all_grades
),
int
(
how_many
)
)
@step
(
u'I move a grading section'
)
...
...
@@ -51,7 +51,7 @@ def confirm_change(step):
range_css
=
'.range'
all_ranges
=
world
.
css_find
(
range_css
)
for
i
in
range
(
len
(
all_ranges
)):
assert
world
.
css_html
(
range_css
,
index
=
i
)
!=
'0-50'
assert
_not_equal
(
world
.
css_html
(
range_css
,
index
=
i
),
'0-50'
)
@step
(
u'I change assignment type "([^"]*)" to "([^"]*)"$'
)
...
...
@@ -59,7 +59,7 @@ def change_assignment_name(step, old_name, new_name):
name_id
=
'#course-grading-assignment-name'
index
=
get_type_index
(
old_name
)
f
=
world
.
css_find
(
name_id
)[
index
]
assert
index
!=
-
1
assert
_not_equal
(
index
,
-
1
)
for
count
in
range
(
len
(
old_name
)):
f
.
_element
.
send_keys
(
Keys
.
END
,
Keys
.
BACK_SPACE
)
f
.
_element
.
send_keys
(
new_name
)
...
...
@@ -78,7 +78,10 @@ def main_course_page(step):
def
see_assignment_name
(
step
,
do_not
,
name
):
assignment_menu_css
=
'ul.menu > li > a'
# First assert that it is there, make take a bit to redraw
assert
world
.
css_find
(
assignment_menu_css
)
assert_true
(
world
.
css_find
(
assignment_menu_css
),
msg
=
"Could not find assignment menu"
)
assignment_menu
=
world
.
css_find
(
assignment_menu_css
)
allnames
=
[
item
.
html
for
item
in
assignment_menu
]
...
...
@@ -113,7 +116,7 @@ def populate_course(step):
def
changes_not_persisted
(
step
):
reload_the_page
(
step
)
name_id
=
'#course-grading-assignment-name'
assert
(
world
.
css_value
(
name_id
)
==
'Homework'
)
assert
_equal
(
world
.
css_value
(
name_id
),
'Homework'
)
@step
(
u'I see the assignment type "(.*)"$'
)
...
...
@@ -121,7 +124,7 @@ def i_see_the_assignment_type(_step, name):
assignment_css
=
'#course-grading-assignment-name'
assignments
=
world
.
css_find
(
assignment_css
)
types
=
[
ele
[
'value'
]
for
ele
in
assignments
]
assert
name
in
types
assert
_in
(
name
,
types
)
@step
(
u'I change the highest grade range to "(.*)"$'
)
...
...
@@ -135,15 +138,15 @@ def change_grade_range(_step, range_name):
def
i_see_highest_grade_range
(
_step
,
range_name
):
range_css
=
'span.letter-grade'
grade
=
world
.
css_find
(
range_css
)
.
first
assert
grade
.
value
==
range_name
,
"{0} != {1}"
.
format
(
grade
.
value
,
range_name
)
assert
_equal
(
grade
.
value
,
range_name
)
@step
(
u'I cannot edit the "Fail" grade range$'
)
def
cannot_edit_fail
(
_step
):
range_css
=
'span.letter-grade'
ranges
=
world
.
css_find
(
range_css
)
assert
len
(
ranges
)
==
2
assert
ranges
.
last
.
value
!=
'Failure'
assert
_equal
(
len
(
ranges
),
2
)
assert
_not_equal
(
ranges
.
last
.
value
,
'Failure'
)
# try to change the grade range -- this should throw an exception
try
:
...
...
@@ -153,14 +156,23 @@ def cannot_edit_fail(_step):
# check to be sure that nothing has changed
ranges
=
world
.
css_find
(
range_css
)
assert
len
(
ranges
)
==
2
assert
ranges
.
last
.
value
!=
'Failure'
assert
_equal
(
len
(
ranges
),
2
)
assert
_not_equal
(
ranges
.
last
.
value
,
'Failure'
)
@step
(
u'I change the grace period to "(.*)"$'
)
def
i_change_grace_period
(
_step
,
grace_period
):
grace_period_css
=
'#course-grading-graceperiod'
ele
=
world
.
css_find
(
grace_period_css
)
.
first
# Sometimes it takes a moment for the JavaScript
# to populate the field. If we don't wait for
# this to happen, then we can end up with
# an invalid value (e.g. "00:0048:00")
# which prevents us from saving.
assert_true
(
world
.
css_has_value
(
grace_period_css
,
"00:00"
,
allow_blank
=
False
))
# Set the new grace period
ele
.
value
=
grace_period
...
...
@@ -168,7 +180,7 @@ def i_change_grace_period(_step, grace_period):
def
the_grace_period_is
(
_step
,
grace_period
):
grace_period_css
=
'#course-grading-graceperiod'
ele
=
world
.
css_find
(
grace_period_css
)
.
first
assert
ele
.
value
==
grace_period
assert
_equal
(
ele
.
value
,
grace_period
)
def
get_type_index
(
name
):
...
...
cms/djangoapps/contentstore/features/video-editor.py
View file @
3257a7ba
...
...
@@ -32,18 +32,21 @@ def shows_captions(_step, show_captions):
@step
(
'I see the correct video settings and default values$'
)
def
correct_video_settings
(
_step
):
world
.
verify_all_setting_entries
([[
'Display Name'
,
'Video'
,
False
],
[
'Download Track'
,
''
,
False
],
[
'Download Video'
,
''
,
False
],
[
'End Time'
,
'0'
,
False
],
[
'HTML5 Timed Transcript'
,
''
,
False
],
[
'Show Captions'
,
'True'
,
False
],
[
'Start Time'
,
'0'
,
False
],
[
'Video Sources'
,
''
,
False
],
[
'Youtube ID'
,
'OEoXaMPEzfM'
,
False
],
[
'Youtube ID for .75x speed'
,
''
,
False
],
[
'Youtube ID for 1.25x speed'
,
''
,
False
],
[
'Youtube ID for 1.5x speed'
,
''
,
False
]])
expected_entries
=
[
[
'Display Name'
,
'Video'
,
False
],
[
'Download Track'
,
''
,
False
],
[
'Download Video'
,
''
,
False
],
[
'End Time'
,
'0'
,
False
],
[
'HTML5 Timed Transcript'
,
''
,
False
],
[
'Show Captions'
,
'True'
,
False
],
[
'Start Time'
,
'0'
,
False
],
[
'Video Sources'
,
''
,
False
],
[
'Youtube ID'
,
'OEoXaMPEzfM'
,
False
],
[
'Youtube ID for .75x speed'
,
''
,
False
],
[
'Youtube ID for 1.25x speed'
,
''
,
False
],
[
'Youtube ID for 1.5x speed'
,
''
,
False
]
]
world
.
verify_all_setting_entries
(
expected_entries
)
@step
(
'my video display name change is persisted on save$'
)
...
...
@@ -52,4 +55,8 @@ def video_name_persisted(step):
reload_the_page
(
step
)
world
.
wait_for_xmodule
()
world
.
edit_component
()
world
.
verify_setting_entry
(
world
.
get_setting_entry
(
'Display Name'
),
'Display Name'
,
'3.4'
,
True
)
world
.
verify_setting_entry
(
world
.
get_setting_entry
(
'Display Name'
),
'Display Name'
,
'3.4'
,
True
)
common/djangoapps/terrain/course_helpers.py
View file @
3257a7ba
...
...
@@ -41,13 +41,13 @@ def log_in(username='robot', password='test', email='robot@edx.org', name='Robot
@world.absorb
def
register_by_course_id
(
course_id
,
is_staff
=
False
):
create_user
(
'robot'
,
'password'
)
u
=
User
.
objects
.
get
(
username
=
'robot'
)
def
register_by_course_id
(
course_id
,
username
=
'robot'
,
password
=
'test'
,
is_staff
=
False
):
create_user
(
username
,
password
)
u
ser
=
User
.
objects
.
get
(
username
=
username
)
if
is_staff
:
u
.
is_staff
=
True
u
.
save
()
CourseEnrollment
.
enroll
(
u
,
course_id
)
u
ser
.
is_staff
=
True
u
ser
.
save
()
CourseEnrollment
.
enroll
(
u
ser
,
course_id
)
@world.absorb
...
...
common/djangoapps/terrain/ui_helpers.py
View file @
3257a7ba
...
...
@@ -34,7 +34,7 @@ def wait(seconds):
def
wait_for_js_variable_truthy
(
variable
):
"""
Using Selenium's `execute_async_script` function, poll the Javascript
envi
or
nment until the given variable is defined and truthy. This process
envi
ro
nment until the given variable is defined and truthy. This process
guards against page reloads, and seamlessly retries on the next page.
"""
js
=
"""
...
...
@@ -194,8 +194,51 @@ def is_css_not_present(css_selector, wait_time=5):
@world.absorb
def
css_has_text
(
css_selector
,
text
,
index
=
0
):
return
world
.
css_text
(
css_selector
,
index
=
index
)
==
text
def
css_has_text
(
css_selector
,
text
,
index
=
0
,
strip
=
False
,
allow_blank
=
True
):
"""
Return a boolean indicating whether the element with `css_selector`
has `text`.
If `strip` is True, strip whitespace at beginning/end of both
strings before comparing.
If `allow_blank` is False, wait for the element to have non-empty
text before making the assertion. This is useful for elements
that are populated by JavaScript after the page loads.
If there are multiple elements matching the css selector,
use `index` to indicate which one.
"""
if
not
allow_blank
:
world
.
wait_for
(
lambda
_
:
world
.
css_text
(
css_selector
,
index
=
index
))
actual_text
=
world
.
css_text
(
css_selector
,
index
=
index
)
if
strip
:
actual_text
=
actual_text
.
strip
()
text
=
text
.
strip
()
return
actual_text
==
text
@world.absorb
def
css_has_value
(
css_selector
,
value
,
index
=
0
,
allow_blank
=
False
):
"""
Return a boolean indicating whether the element with
`css_selector` has the specified `value`.
If `allow_blank` is False, wait for the element to have
a value that is a non-empty string.
If there are multiple elements matching the css selector,
use `index` to indicate which one.
"""
if
not
allow_blank
:
world
.
wait_for
(
lambda
_
:
world
.
css_value
(
css_selector
,
index
=
index
))
return
world
.
css_value
(
css_selector
,
index
=
index
)
==
value
@world.absorb
...
...
lms/djangoapps/courseware/features/navigation.feature
View file @
3257a7ba
@shard_1
Feature
:
LMS.Navigate Course
As a student in an edX course
In order to
view the course properly
In order to
access courseware
I want to be able to navigate through the content
Scenario
:
I
can navigate to a section
Given
I am viewing a course with multiple sections
When
I
click on section
"2"
Then
I s
hould see the content of section
"2"
When
I
navigate to a section
Then
I s
ee the content of the section
Scenario
:
I
can navigate to subsections
Given
I am viewing a section with multiple subsections
When
I
click on subsection
"2"
Then
I s
hould see the content of subsection
"2"
When
I
navigate to a subsection
Then
I s
ee the content of the subsection
Scenario
:
I
can navigate to sequences
Given
I am viewing a section with multiple sequences
When
I
click on sequence
"2"
Then
I s
hould see the content of sequence
"2"
When
I
navigate to an item in a sequence
Then
I s
ee the content of the sequence item
Scenario
:
I
can
go back to where I was after I log out and back in
Scenario
:
I
can
return to the last section I visited
Given
I am viewing a course with multiple sections
When
I click on section
"2"
And
I return later
Then
I should see that I was most recently in section
"2"
When
I navigate to a section
And
I see the content of the section
And
I return to the courseware
Then
I see that I was most recently in the subsection
lms/djangoapps/courseware/features/navigation.py
View file @
3257a7ba
This diff is collapsed.
Click to expand it.
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