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
26a05f2a
Commit
26a05f2a
authored
Jun 21, 2013
by
Jonah Stanley
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #140 from edx/jonahstanley/add-courseteam-tests
Jonahstanley/add courseteam tests
parents
a36aee5b
d632ffe9
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
475 additions
and
17 deletions
+475
-17
cms/djangoapps/contentstore/features/common.py
+16
-13
cms/djangoapps/contentstore/features/course-team.feature
+34
-0
cms/djangoapps/contentstore/features/course-team.py
+67
-0
cms/djangoapps/contentstore/features/course-updates.feature
+37
-0
cms/djangoapps/contentstore/features/course-updates.py
+84
-0
cms/djangoapps/contentstore/features/courses.py
+1
-0
cms/djangoapps/contentstore/features/static-pages.feature
+24
-0
cms/djangoapps/contentstore/features/static-pages.py
+59
-0
cms/djangoapps/contentstore/features/studio-overview-togglesection.py
+2
-1
cms/djangoapps/contentstore/features/upload.feature
+38
-0
cms/djangoapps/contentstore/features/upload.py
+108
-0
common/djangoapps/terrain/course_helpers.py
+3
-3
common/test/data/uploads/test
+2
-0
No files found.
cms/djangoapps/contentstore/features/common.py
View file @
26a05f2a
...
...
@@ -3,7 +3,6 @@
from
lettuce
import
world
,
step
from
nose.tools
import
assert_true
from
nose.tools
import
assert_equal
from
auth.authz
import
get_user_by_email
...
...
@@ -13,8 +12,13 @@ import time
from
logging
import
getLogger
logger
=
getLogger
(
__name__
)
_COURSE_NAME
=
'Robot Super Course'
_COURSE_NUM
=
'999'
_COURSE_ORG
=
'MITx'
########### STEP HELPERS ##############
@step
(
'I (?:visit|access|open) the Studio homepage$'
)
def
i_visit_the_studio_homepage
(
_step
):
# To make this go to port 8001, put
...
...
@@ -54,6 +58,7 @@ def i_have_opened_a_new_course(_step):
####### HELPER FUNCTIONS ##############
def
open_new_course
():
world
.
clear_courses
()
create_studio_user
()
log_into_studio
()
create_a_course
()
...
...
@@ -73,10 +78,11 @@ def create_studio_user(
registration
.
register
(
studio_user
)
registration
.
activate
()
def
fill_in_course_info
(
name
=
'Robot Super Course'
,
org
=
'MITx'
,
num
=
'101'
):
name
=
_COURSE_NAME
,
org
=
_COURSE_ORG
,
num
=
_COURSE_NUM
):
world
.
css_fill
(
'.new-course-name'
,
name
)
world
.
css_fill
(
'.new-course-org'
,
org
)
world
.
css_fill
(
'.new-course-number'
,
num
)
...
...
@@ -85,10 +91,7 @@ def fill_in_course_info(
def
log_into_studio
(
uname
=
'robot'
,
email
=
'robot+studio@edx.org'
,
password
=
'test'
,
is_staff
=
False
):
create_studio_user
(
uname
=
uname
,
email
=
email
,
is_staff
=
is_staff
)
password
=
'test'
):
world
.
browser
.
cookies
.
delete
()
world
.
visit
(
'/'
)
...
...
@@ -106,14 +109,14 @@ def log_into_studio(
def
create_a_course
():
world
.
CourseFactory
.
create
(
org
=
'MITx'
,
course
=
'999'
,
display_name
=
'Robot Super Course'
)
world
.
CourseFactory
.
create
(
org
=
_COURSE_ORG
,
course
=
_COURSE_NUM
,
display_name
=
_COURSE_NAME
)
# Add the user to the instructor group of the course
# so they will have the permissions to see it in studio
g
=
world
.
GroupFactory
.
create
(
name
=
'instructor_MITx/999/Robot_Super_Course'
)
u
=
get_user_by_email
(
'robot+studio@edx.org'
)
u
.
groups
.
add
(
g
)
u
.
save
()
course
=
world
.
GroupFactory
.
create
(
name
=
'instructor_MITx/{course_num}/{course_name}'
.
format
(
course_num
=
_COURSE_NUM
,
course_name
=
_COURSE_NAME
.
replace
(
" "
,
"_"
))
)
u
ser
=
get_user_by_email
(
'robot+studio@edx.org'
)
u
ser
.
groups
.
add
(
course
)
u
ser
.
save
()
world
.
browser
.
reload
()
course_link_css
=
'span.class-name'
...
...
cms/djangoapps/contentstore/features/course-team.feature
0 → 100644
View file @
26a05f2a
Feature
:
Course Team
As a course author, I want to be able to add others to my team
Scenario
:
Users can add other users
Given
I have opened a new course in Studio
And
the user
"alice"
exists
And
I am viewing the course team settings
When
I add
"alice"
to the course team
And
"alice"
logs
in
Then
she does see the course on her page
Scenario
:
Added users cannot delete or add other users
Given
I have opened a new course in Studio
And
the user
"bob"
exists
And
I am viewing the course team settings
When
I add
"bob"
to the course team
And
"bob"
logs
in
Then
he cannot delete users
And
he cannot add users
Scenario
:
Users can delete other users
Given
I have opened a new course in Studio
And
the user
"carol"
exists
And
I am viewing the course team settings
When
I add
"carol"
to the course team
And
I delete
"carol"
from the course team
And
"carol"
logs
in
Then
she does not see the course on her page
Scenario
:
Users cannot add users that do not exist
Given
I have opened a new course in Studio
And
I am viewing the course team settings
When
I add
"dennis"
to the course team
Then
I should see
"Could not find user by email address"
somewhere on the page
cms/djangoapps/contentstore/features/course-team.py
0 → 100644
View file @
26a05f2a
#pylint: disable=C0111
#pylint: disable=W0621
from
lettuce
import
world
,
step
from
common
import
create_studio_user
,
log_into_studio
,
_COURSE_NAME
PASSWORD
=
'test'
EMAIL_EXTENSION
=
'@edx.org'
@step
(
u'I am viewing the course team settings'
)
def
view_grading_settings
(
_step
):
world
.
click_course_settings
()
link_css
=
'li.nav-course-settings-team a'
world
.
css_click
(
link_css
)
@step
(
u'the user "([^"]*)" exists$'
)
def
create_other_user
(
_step
,
name
):
create_studio_user
(
uname
=
name
,
password
=
PASSWORD
,
email
=
(
name
+
EMAIL_EXTENSION
))
@step
(
u'I add "([^"]*)" to the course team'
)
def
add_other_user
(
_step
,
name
):
new_user_css
=
'a.new-user-button'
world
.
css_click
(
new_user_css
)
email_css
=
'input.email-input'
f
=
world
.
css_find
(
email_css
)
f
.
_element
.
send_keys
(
name
,
EMAIL_EXTENSION
)
confirm_css
=
'#add_user'
world
.
css_click
(
confirm_css
)
@step
(
u'I delete "([^"]*)" from the course team'
)
def
delete_other_user
(
_step
,
name
):
to_delete_css
=
'a.remove-user[data-id="{name}{extension}"]'
.
format
(
name
=
name
,
extension
=
EMAIL_EXTENSION
)
world
.
css_click
(
to_delete_css
)
@step
(
u'"([^"]*)" logs in$'
)
def
other_user_login
(
_step
,
name
):
log_into_studio
(
uname
=
name
,
password
=
PASSWORD
,
email
=
name
+
EMAIL_EXTENSION
)
@step
(
u's?he does( not)? see the course on (his|her) page'
)
def
see_course
(
_step
,
doesnt_see_course
,
gender
):
class_css
=
'span.class-name'
all_courses
=
world
.
css_find
(
class_css
)
all_names
=
[
item
.
html
for
item
in
all_courses
]
if
doesnt_see_course
:
assert
not
_COURSE_NAME
in
all_names
else
:
assert
_COURSE_NAME
in
all_names
@step
(
u's?he cannot delete users'
)
def
cannot_delete
(
_step
):
to_delete_css
=
'a.remove-user'
assert
world
.
is_css_not_present
(
to_delete_css
)
@step
(
u's?he cannot add users'
)
def
cannot_add
(
_step
):
add_css
=
'a.new-user'
assert
world
.
is_css_not_present
(
add_css
)
cms/djangoapps/contentstore/features/course-updates.feature
0 → 100644
View file @
26a05f2a
Feature
:
Course updates
As a course author, I want to be able to provide updates to my students
Scenario
:
Users can add updates
Given
I have opened a new course in Studio
And
I go to the course updates page
When
I add a new update with the text
"Hello"
Then
I should see the update
"Hello"
Scenario
:
Users can edit updates
Given
I have opened a new course in Studio
And
I go to the course updates page
When
I add a new update with the text
"Hello"
And
I modify the text to
"Goodbye"
Then
I should see the update
"Goodbye"
Scenario
:
Users can delete updates
Given
I have opened a new course in Studio
And
I go to the course updates page
And
I add a new update with the text
"Hello"
When
I will confirm all alerts
And
I delete the update
Then
I should not see the update
"Hello"
Scenario
:
Users can edit update dates
Given
I have opened a new course in Studio
And
I go to the course updates page
And
I add a new update with the text
"Hello"
When
I edit the date to
"June 1, 2013"
Then
I should see the date
"June 1, 2013"
Scenario
:
Users can change handouts
Given
I have opened a new course in Studio
And
I go to the course updates page
When
I modify the handout to
"<ol>Test</ol>"
Then
I see the handout
"Test"
cms/djangoapps/contentstore/features/course-updates.py
0 → 100644
View file @
26a05f2a
#pylint: disable=C0111
#pylint: disable=W0621
from
lettuce
import
world
,
step
from
selenium.webdriver.common.keys
import
Keys
from
common
import
type_in_codemirror
@step
(
u'I go to the course updates page'
)
def
go_to_updates
(
_step
):
menu_css
=
'li.nav-course-courseware'
updates_css
=
'li.nav-course-courseware-updates'
world
.
css_click
(
menu_css
)
world
.
css_click
(
updates_css
)
@step
(
u'I add a new update with the text "([^"]*)"$'
)
def
add_update
(
_step
,
text
):
update_css
=
'a.new-update-button'
world
.
css_click
(
update_css
)
change_text
(
text
)
@step
(
u'I should( not)? see the update "([^"]*)"$'
)
def
check_update
(
_step
,
doesnt_see_update
,
text
):
update_css
=
'div.update-contents'
update
=
world
.
css_find
(
update_css
)
if
doesnt_see_update
:
assert
len
(
update
)
==
0
or
not
text
in
update
.
html
else
:
assert
text
in
update
.
html
@step
(
u'I modify the text to "([^"]*)"$'
)
def
modify_update
(
_step
,
text
):
button_css
=
'div.post-preview a.edit-button'
world
.
css_click
(
button_css
)
change_text
(
text
)
@step
(
u'I delete the update$'
)
def
click_button
(
_step
):
button_css
=
'div.post-preview a.delete-button'
world
.
css_click
(
button_css
)
@step
(
u'I edit the date to "([^"]*)"$'
)
def
change_date
(
_step
,
new_date
):
button_css
=
'div.post-preview a.edit-button'
world
.
css_click
(
button_css
)
date_css
=
'input.date'
date
=
world
.
css_find
(
date_css
)
for
i
in
range
(
len
(
date
.
value
)):
date
.
_element
.
send_keys
(
Keys
.
END
,
Keys
.
BACK_SPACE
)
date
.
_element
.
send_keys
(
new_date
)
save_css
=
'a.save-button'
world
.
css_click
(
save_css
)
@step
(
u'I should see the date "([^"]*)"$'
)
def
check_date
(
_step
,
date
):
date_css
=
'span.date-display'
date_html
=
world
.
css_find
(
date_css
)
assert
date
==
date_html
.
html
@step
(
u'I modify the handout to "([^"]*)"$'
)
def
edit_handouts
(
_step
,
text
):
edit_css
=
'div.course-handouts > a.edit-button'
world
.
css_click
(
edit_css
)
change_text
(
text
)
@step
(
u'I see the handout "([^"]*)"$'
)
def
check_handout
(
_step
,
handout
):
handout_css
=
'div.handouts-content'
handouts
=
world
.
css_find
(
handout_css
)
assert
handout
in
handouts
.
html
def
change_text
(
text
):
type_in_codemirror
(
0
,
text
)
save_css
=
'a.save-button'
world
.
css_click
(
save_css
)
cms/djangoapps/contentstore/features/courses.py
View file @
26a05f2a
...
...
@@ -10,6 +10,7 @@ from common import *
@step
(
'There are no courses$'
)
def
no_courses
(
step
):
world
.
clear_courses
()
create_studio_user
()
@step
(
'I click the New Course button$'
)
...
...
cms/djangoapps/contentstore/features/static-pages.feature
0 → 100644
View file @
26a05f2a
Feature
:
Static Pages
As a course author, I want to be able to add static pages
Scenario
:
Users can add static pages
Given
I have opened a new course in Studio
And
I go to the static pages page
When
I add a new page
Then
I should see a
"Empty"
static page
Scenario
:
Users can delete static pages
Given
I have opened a new course in Studio
And
I go to the static pages page
And
I add a new page
When
I will confirm all alerts
And
I
"delete"
the
"Empty"
page
Then
I should not see a
"Empty"
static page
Scenario
:
Users can edit static pages
Given
I have opened a new course in Studio
And
I go to the static pages page
And
I add a new page
When
I
"edit"
the
"Empty"
page
And
I change the name to
"New"
Then
I should see a
"New"
static page
cms/djangoapps/contentstore/features/static-pages.py
0 → 100644
View file @
26a05f2a
#pylint: disable=C0111
#pylint: disable=W0621
from
lettuce
import
world
,
step
from
selenium.webdriver.common.keys
import
Keys
@step
(
u'I go to the static pages page'
)
def
go_to_static
(
_step
):
menu_css
=
'li.nav-course-courseware'
static_css
=
'li.nav-course-courseware-pages'
world
.
css_find
(
menu_css
)
.
click
()
world
.
css_find
(
static_css
)
.
click
()
@step
(
u'I add a new page'
)
def
add_page
(
_step
):
button_css
=
'a.new-button'
world
.
css_find
(
button_css
)
.
click
()
@step
(
u'I should( not)? see a "([^"]*)" static page$'
)
def
see_page
(
_step
,
doesnt
,
page
):
index
=
get_index
(
page
)
if
doesnt
:
assert
index
==
-
1
else
:
assert
index
!=
-
1
@step
(
u'I "([^"]*)" the "([^"]*)" page$'
)
def
click_edit_delete
(
_step
,
edit_delete
,
page
):
button_css
=
'a.
%
s-button'
%
edit_delete
index
=
get_index
(
page
)
assert
index
!=
-
1
world
.
css_find
(
button_css
)[
index
]
.
click
()
@step
(
u'I change the name to "([^"]*)"$'
)
def
change_name
(
_step
,
new_name
):
settings_css
=
'#settings-mode'
world
.
css_find
(
settings_css
)
.
click
()
input_css
=
'input.setting-input'
name_input
=
world
.
css_find
(
input_css
)
old_name
=
name_input
.
value
for
count
in
range
(
len
(
old_name
)):
name_input
.
_element
.
send_keys
(
Keys
.
END
,
Keys
.
BACK_SPACE
)
name_input
.
_element
.
send_keys
(
new_name
)
save_button
=
'a.save-button'
world
.
css_find
(
save_button
)
.
click
()
def
get_index
(
name
):
page_name_css
=
'section[data-type="HTMLModule"]'
all_pages
=
world
.
css_find
(
page_name_css
)
for
i
in
range
(
len
(
all_pages
)):
if
all_pages
[
i
]
.
html
==
'
\n
{name}
\n
'
.
format
(
name
=
name
):
return
i
return
-
1
cms/djangoapps/contentstore/features/studio-overview-togglesection.py
View file @
26a05f2a
...
...
@@ -50,7 +50,8 @@ def have_a_course_with_two_sections(step):
@step
(
u'I navigate to the course overview page$'
)
def
navigate_to_the_course_overview_page
(
step
):
log_into_studio
(
is_staff
=
True
)
create_studio_user
(
is_staff
=
True
)
log_into_studio
()
course_locator
=
'.class-name'
world
.
css_click
(
course_locator
)
...
...
cms/djangoapps/contentstore/features/upload.feature
0 → 100644
View file @
26a05f2a
Feature
:
Upload Files
As a course author, I want to be able to upload files for my students
Scenario
:
Users can upload files
Given
I have opened a new course in Studio
And
I go to the files and uploads page
When
I upload the file
"test"
Then
I should see the file
"test"
was uploaded
And
The url for the file
"test"
is valid
Scenario
:
Users can update files
Given
I have opened a new course in studio
And
I go to the files and uploads page
When
I upload the file
"test"
And
I upload the file
"test"
Then
I should see only one
"test"
Scenario
:
Users can delete uploaded files
Given
I have opened a new course in studio
And
I go to the files and uploads page
When
I upload the file
"test"
And
I delete the file
"test"
Then
I should not see the file
"test"
was uploaded
Scenario
:
Users can download files
Given
I have opened a new course in studio
And
I go to the files and uploads page
When
I upload the file
"test"
Then
I can download the correct
"test"
file
Scenario
:
Users can download updated files
Given
I have opened a new course in studio
And
I go to the files and uploads page
When
I upload the file
"test"
And
I modify
"test"
And
I reload the page
And
I upload the file
"test"
Then
I can download the correct
"test"
file
cms/djangoapps/contentstore/features/upload.py
0 → 100644
View file @
26a05f2a
#pylint: disable=C0111
#pylint: disable=W0621
from
lettuce
import
world
,
step
from
django.conf
import
settings
import
requests
import
string
import
random
import
os
TEST_ROOT
=
settings
.
COMMON_TEST_DATA_ROOT
HTTP_PREFIX
=
"http://localhost:8001"
@step
(
u'I go to the files and uploads page'
)
def
go_to_uploads
(
_step
):
menu_css
=
'li.nav-course-courseware'
uploads_css
=
'li.nav-course-courseware-uploads'
world
.
css_find
(
menu_css
)
.
click
()
world
.
css_find
(
uploads_css
)
.
click
()
@step
(
u'I upload the file "([^"]*)"$'
)
def
upload_file
(
_step
,
file_name
):
upload_css
=
'a.upload-button'
world
.
css_find
(
upload_css
)
.
click
()
file_css
=
'input.file-input'
upload
=
world
.
css_find
(
file_css
)
#uploading the file itself
path
=
os
.
path
.
join
(
TEST_ROOT
,
'uploads/'
,
file_name
)
upload
.
_element
.
send_keys
(
os
.
path
.
abspath
(
path
))
close_css
=
'a.close-button'
world
.
css_find
(
close_css
)
.
click
()
@step
(
u'I should( not)? see the file "([^"]*)" was uploaded$'
)
def
check_upload
(
_step
,
do_not_see_file
,
file_name
):
index
=
get_index
(
file_name
)
if
do_not_see_file
:
assert
index
==
-
1
else
:
assert
index
!=
-
1
@step
(
u'The url for the file "([^"]*)" is valid$'
)
def
check_url
(
_step
,
file_name
):
r
=
get_file
(
file_name
)
assert
r
.
status_code
==
200
@step
(
u'I delete the file "([^"]*)"$'
)
def
delete_file
(
_step
,
file_name
):
index
=
get_index
(
file_name
)
assert
index
!=
-
1
delete_css
=
"a.remove-asset-button"
world
.
css_click
(
delete_css
,
index
=
index
)
prompt_confirm_css
=
'li.nav-item > a.action-primary'
world
.
css_click
(
prompt_confirm_css
)
@step
(
u'I should see only one "([^"]*)"$'
)
def
no_duplicate
(
_step
,
file_name
):
names_css
=
'td.name-col > a.filename'
all_names
=
world
.
css_find
(
names_css
)
only_one
=
False
for
i
in
range
(
len
(
all_names
)):
if
file_name
==
all_names
[
i
]
.
html
:
only_one
=
not
only_one
assert
only_one
@step
(
u'I can download the correct "([^"]*)" file$'
)
def
check_download
(
_step
,
file_name
):
path
=
os
.
path
.
join
(
TEST_ROOT
,
'uploads/'
,
file_name
)
with
open
(
os
.
path
.
abspath
(
path
),
'r'
)
as
cur_file
:
cur_text
=
cur_file
.
read
()
r
=
get_file
(
file_name
)
downloaded_text
=
r
.
text
assert
cur_text
==
downloaded_text
@step
(
u'I modify "([^"]*)"$'
)
def
modify_upload
(
_step
,
file_name
):
new_text
=
''
.
join
(
random
.
choice
(
string
.
ascii_uppercase
+
string
.
digits
)
for
x
in
range
(
10
))
path
=
os
.
path
.
join
(
TEST_ROOT
,
'uploads/'
,
file_name
)
with
open
(
os
.
path
.
abspath
(
path
),
'w'
)
as
cur_file
:
cur_file
.
write
(
new_text
)
def
get_index
(
file_name
):
names_css
=
'td.name-col > a.filename'
all_names
=
world
.
css_find
(
names_css
)
for
i
in
range
(
len
(
all_names
)):
if
file_name
==
all_names
[
i
]
.
html
:
return
i
return
-
1
def
get_file
(
file_name
):
index
=
get_index
(
file_name
)
assert
index
!=
-
1
url_css
=
'input.embeddable-xml-input'
url
=
world
.
css_find
(
url_css
)[
index
]
.
value
return
requests
.
get
(
HTTP_PREFIX
+
url
)
common/djangoapps/terrain/course_helpers.py
View file @
26a05f2a
...
...
@@ -10,7 +10,8 @@ from django.contrib.auth import authenticate, login
from
django.contrib.auth.middleware
import
AuthenticationMiddleware
from
django.contrib.sessions.middleware
import
SessionMiddleware
from
student.models
import
CourseEnrollment
from
xmodule.modulestore.django
import
_MODULESTORES
,
modulestore
from
xmodule.modulestore.django
import
modulestore
from
xmodule.contentstore.django
import
contentstore
from
xmodule.templates
import
update_templates
from
bs4
import
BeautifulSoup
import
os.path
...
...
@@ -110,7 +111,6 @@ def save_the_course_content(path='/tmp'):
u
=
world
.
browser
.
url
section_url
=
u
[
u
.
find
(
'courseware/'
)
+
11
:]
if
not
os
.
path
.
exists
(
path
):
os
.
makedirs
(
path
)
...
...
@@ -129,6 +129,6 @@ def clear_courses():
# (though it shouldn't), do this manually
# from the bash shell to drop it:
# $ mongo test_xmodule --eval "db.dropDatabase()"
_MODULESTORES
=
{}
modulestore
()
.
collection
.
drop
()
update_templates
(
modulestore
(
'direct'
))
contentstore
()
.
fs_files
.
drop
()
common/test/data/uploads/test
0 → 100644
View file @
26a05f2a
R2FUIGM88K
\ No newline at end of file
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