Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
E
edx-platform-release
Manage
Activity
Members
Labels
Plan
Issues
0
Issue boards
Milestones
Wiki
Code
Merge requests
1
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Package Registry
Model registry
Operate
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Hsin-Yu Chien
edx-platform-release
Commits
8569cb35
Commit
8569cb35
authored
7 years ago
by
Robert Raposa
Browse files
Options
Downloads
Patches
Plain Diff
Fix logic error in calculating last accessed.
parent
698475f5
Loading
Loading
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
openedx/features/course_experience/tests/views/test_course_outline.py
+159
-46
159 additions, 46 deletions
...ures/course_experience/tests/views/test_course_outline.py
openedx/features/course_experience/utils.py
+7
-7
7 additions, 7 deletions
openedx/features/course_experience/utils.py
with
166 additions
and
53 deletions
openedx/features/course_experience/tests/views/test_course_outline.py
+
159
−
46
View file @
8569cb35
...
...
@@ -13,6 +13,7 @@ from pyquery import PyQuery as pq
from
courseware.tests.factories
import
StaffFactory
from
student.models
import
CourseEnrollment
from
student.tests.factories
import
UserFactory
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore.tests.django_utils
import
SharedModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
from
xmodule.course_module
import
DEFAULT_START_DATE
...
...
@@ -26,11 +27,13 @@ PAST_DAY = datetime.datetime.now() - datetime.timedelta(days=30)
class
TestCourseOutlinePage
(
SharedModuleStoreTestCase
):
"""
Test the
new
course outline view.
Test the course outline view.
"""
@classmethod
def
setUpClass
(
cls
):
"""
Set up the simplest course possible.
"""
"""
Set up an array of various courses to be tested.
"""
# setUpClassAndTestData() already calls setUpClass on SharedModuleStoreTestCase
# pylint: disable=super-method-not-called
with
super
(
TestCourseOutlinePage
,
cls
).
setUpClassAndTestData
():
...
...
@@ -38,40 +41,40 @@ class TestCourseOutlinePage(SharedModuleStoreTestCase):
course
=
CourseFactory
.
create
()
with
cls
.
store
.
bulk_operations
(
course
.
id
):
chapter
=
ItemFactory
.
create
(
category
=
'
chapter
'
,
parent_location
=
course
.
location
)
se
ction
=
ItemFactory
.
create
(
category
=
'
sequential
'
,
parent_location
=
chapter
.
location
)
vertical
=
ItemFactory
.
create
(
category
=
'
vertical
'
,
parent_location
=
se
ction
.
location
)
se
quential
=
ItemFactory
.
create
(
category
=
'
sequential
'
,
parent_location
=
chapter
.
location
)
vertical
=
ItemFactory
.
create
(
category
=
'
vertical
'
,
parent_location
=
se
quential
.
location
)
course
.
children
=
[
chapter
]
chapter
.
children
=
[
se
ction
]
se
ction
.
children
=
[
vertical
]
chapter
.
children
=
[
se
quential
]
se
quential
.
children
=
[
vertical
]
cls
.
courses
.
append
(
course
)
course
=
CourseFactory
.
create
()
with
cls
.
store
.
bulk_operations
(
course
.
id
):
chapter
=
ItemFactory
.
create
(
category
=
'
chapter
'
,
parent_location
=
course
.
location
)
se
ction
=
ItemFactory
.
create
(
category
=
'
sequential
'
,
parent_location
=
chapter
.
location
)
se
ction
2
=
ItemFactory
.
create
(
category
=
'
sequential
'
,
parent_location
=
chapter
.
location
)
vertical
=
ItemFactory
.
create
(
category
=
'
vertical
'
,
parent_location
=
se
ction
.
location
)
vertical2
=
ItemFactory
.
create
(
category
=
'
vertical
'
,
parent_location
=
se
ction
2
.
location
)
se
quential
=
ItemFactory
.
create
(
category
=
'
sequential
'
,
parent_location
=
chapter
.
location
)
se
quential
2
=
ItemFactory
.
create
(
category
=
'
sequential
'
,
parent_location
=
chapter
.
location
)
vertical
=
ItemFactory
.
create
(
category
=
'
vertical
'
,
parent_location
=
se
quential
.
location
)
vertical2
=
ItemFactory
.
create
(
category
=
'
vertical
'
,
parent_location
=
se
quential
2
.
location
)
course
.
children
=
[
chapter
]
chapter
.
children
=
[
se
ction
,
section
2
]
se
ction
.
children
=
[
vertical
]
se
ction
2
.
children
=
[
vertical2
]
chapter
.
children
=
[
se
quential
,
sequential
2
]
se
quential
.
children
=
[
vertical
]
se
quential
2
.
children
=
[
vertical2
]
cls
.
courses
.
append
(
course
)
course
=
CourseFactory
.
create
()
with
cls
.
store
.
bulk_operations
(
course
.
id
):
chapter
=
ItemFactory
.
create
(
category
=
'
chapter
'
,
parent_location
=
course
.
location
)
se
ction
=
ItemFactory
.
create
(
se
quential
=
ItemFactory
.
create
(
category
=
'
sequential
'
,
parent_location
=
chapter
.
location
,
due
=
datetime
.
datetime
.
now
(),
graded
=
True
,
format
=
'
Homework
'
,
)
vertical
=
ItemFactory
.
create
(
category
=
'
vertical
'
,
parent_location
=
se
ction
.
location
)
vertical
=
ItemFactory
.
create
(
category
=
'
vertical
'
,
parent_location
=
se
quential
.
location
)
course
.
children
=
[
chapter
]
chapter
.
children
=
[
se
ction
]
se
ction
.
children
=
[
vertical
]
chapter
.
children
=
[
se
quential
]
se
quential
.
children
=
[
vertical
]
cls
.
courses
.
append
(
course
)
@classmethod
...
...
@@ -100,15 +103,82 @@ class TestCourseOutlinePage(SharedModuleStoreTestCase):
for
chapter
in
course
.
children
:
self
.
assertIn
(
chapter
.
display_name
,
response_content
)
self
.
assertTrue
(
chapter
.
children
)
for
se
ction
in
chapter
.
children
:
self
.
assertIn
(
se
ction
.
display_name
,
response_content
)
if
se
ction
.
graded
:
self
.
assertIn
(
se
ction
.
due
.
strftime
(
'
%Y-%m-%d %H:%M:%S
'
),
response_content
)
self
.
assertIn
(
se
ction
.
format
,
response_content
)
self
.
assertTrue
(
se
ction
.
children
)
for
vertical
in
se
ction
.
children
:
for
se
quential
in
chapter
.
children
:
self
.
assertIn
(
se
quential
.
display_name
,
response_content
)
if
se
quential
.
graded
:
self
.
assertIn
(
se
quential
.
due
.
strftime
(
'
%Y-%m-%d %H:%M:%S
'
),
response_content
)
self
.
assertIn
(
se
quential
.
format
,
response_content
)
self
.
assertTrue
(
se
quential
.
children
)
for
vertical
in
se
quential
.
children
:
self
.
assertNotIn
(
vertical
.
display_name
,
response_content
)
class
TestCourseOutlineResumeCourse
(
SharedModuleStoreTestCase
):
"""
Test start course and resume course for the course outline view.
Technically, this mixes course home and course outline tests, but checking
the counts of start/resume course should be done together to avoid false
positives.
"""
@classmethod
def
setUpClass
(
cls
):
"""
Creates a test course that can be used for non-destructive tests
"""
# setUpClassAndTestData() already calls setUpClass on SharedModuleStoreTestCase
# pylint: disable=super-method-not-called
with
super
(
TestCourseOutlineResumeCourse
,
cls
).
setUpClassAndTestData
():
cls
.
course
=
cls
.
create_test_course
()
@classmethod
def
setUpTestData
(
cls
):
"""
Set up and enroll our fake user in the course.
"""
cls
.
user
=
UserFactory
(
password
=
TEST_PASSWORD
)
CourseEnrollment
.
enroll
(
cls
.
user
,
cls
.
course
.
id
)
@classmethod
def
create_test_course
(
cls
):
"""
Creates a test course.
"""
course
=
CourseFactory
.
create
()
with
cls
.
store
.
bulk_operations
(
course
.
id
):
chapter
=
ItemFactory
.
create
(
category
=
'
chapter
'
,
parent_location
=
course
.
location
)
sequential
=
ItemFactory
.
create
(
category
=
'
sequential
'
,
parent_location
=
chapter
.
location
)
sequential2
=
ItemFactory
.
create
(
category
=
'
sequential
'
,
parent_location
=
chapter
.
location
)
vertical
=
ItemFactory
.
create
(
category
=
'
vertical
'
,
parent_location
=
sequential
.
location
)
vertical2
=
ItemFactory
.
create
(
category
=
'
vertical
'
,
parent_location
=
sequential2
.
location
)
course
.
children
=
[
chapter
]
chapter
.
children
=
[
sequential
,
sequential2
]
sequential
.
children
=
[
vertical
]
sequential2
.
children
=
[
vertical2
]
if
hasattr
(
cls
,
'
user
'
):
CourseEnrollment
.
enroll
(
cls
.
user
,
course
.
id
)
return
course
def
setUp
(
self
):
"""
Set up for the tests.
"""
super
(
TestCourseOutlineResumeCourse
,
self
).
setUp
()
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
TEST_PASSWORD
)
def
visit_sequential
(
self
,
course
,
chapter
,
sequential
):
"""
Navigates to the provided sequential.
"""
last_accessed_url
=
reverse
(
'
courseware_section
'
,
kwargs
=
{
'
course_id
'
:
course
.
id
.
to_deprecated_string
(),
'
chapter
'
:
chapter
.
url_name
,
'
section
'
:
sequential
.
url_name
,
}
)
self
.
assertEqual
(
200
,
self
.
client
.
get
(
last_accessed_url
).
status_code
)
def
test_start_course
(
self
):
"""
Tests that the start course button appears when the course has never been accessed.
...
...
@@ -117,7 +187,7 @@ class TestCourseOutlinePage(SharedModuleStoreTestCase):
start/resume course should be done together to not get a false positive.
"""
course
=
self
.
course
s
[
0
]
course
=
self
.
course
response
=
self
.
client
.
get
(
course_home_url
(
course
))
self
.
assertEqual
(
response
.
status_code
,
200
)
...
...
@@ -131,25 +201,42 @@ class TestCourseOutlinePage(SharedModuleStoreTestCase):
def
test_resume_course
(
self
):
"""
Tests that two resume course buttons appear when the course has been accessed.
"""
course
=
self
.
course
# first navigate to a sequential to make it the last accessed
chapter
=
course
.
children
[
0
]
sequential
=
chapter
.
children
[
0
]
self
.
visit_sequential
(
course
,
chapter
,
sequential
)
Technically, this is a mix of a course home and course outline test, but checking the counts of start/resume
course should be done together to not get a false positive.
# check resume course buttons
response
=
self
.
client
.
get
(
course_home_url
(
course
))
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertContains
(
response
,
'
Start Course
'
,
count
=
0
)
self
.
assertContains
(
response
,
'
Resume Course
'
,
count
=
2
)
content
=
pq
(
response
.
content
)
self
.
assertTrue
(
content
(
'
.action-resume-course
'
).
attr
(
'
href
'
).
endswith
(
'
/sequential/
'
+
sequential
.
url_name
))
def
test_resume_course_deleted_sequential
(
self
):
"""
course
=
self
.
courses
[
0
]
Tests resume course when the last accessed sequential is deleted and
there is another sequential in the vertical.
# first navigate to a section to make it the last accessed
"""
course
=
self
.
create_test_course
()
# first navigate to a sequential to make it the last accessed
chapter
=
course
.
children
[
0
]
section
=
chapter
.
children
[
0
]
last_accessed_url
=
reverse
(
'
courseware_section
'
,
kwargs
=
{
'
course_id
'
:
course
.
id
.
to_deprecated_string
(),
'
chapter
'
:
chapter
.
url_name
,
'
section
'
:
section
.
url_name
,
}
)
self
.
assertEqual
(
200
,
self
.
client
.
get
(
last_accessed_url
).
status_code
)
self
.
assertGreaterEqual
(
len
(
chapter
.
children
),
2
)
sequential
=
chapter
.
children
[
0
]
sequential2
=
chapter
.
children
[
1
]
self
.
visit_sequential
(
course
,
chapter
,
sequential
)
# remove one of the sequentials from the chapter
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
,
course
.
id
):
self
.
store
.
delete_item
(
sequential
.
location
,
self
.
user
.
id
)
# pylint: disable=no-member
# check resume course buttons
response
=
self
.
client
.
get
(
course_home_url
(
course
))
...
...
@@ -159,7 +246,33 @@ class TestCourseOutlinePage(SharedModuleStoreTestCase):
self
.
assertContains
(
response
,
'
Resume Course
'
,
count
=
2
)
content
=
pq
(
response
.
content
)
self
.
assertTrue
(
content
(
'
.action-resume-course
'
).
attr
(
'
href
'
).
endswith
(
'
/sequential/
'
+
section
.
url_name
))
self
.
assertTrue
(
content
(
'
.action-resume-course
'
).
attr
(
'
href
'
).
endswith
(
'
/sequential/
'
+
sequential2
.
url_name
))
def
test_resume_course_deleted_sequentials
(
self
):
"""
Tests resume course when the last accessed sequential is deleted and
there are no sequentials left in the vertical.
"""
course
=
self
.
create_test_course
()
# first navigate to a sequential to make it the last accessed
chapter
=
course
.
children
[
0
]
self
.
assertEqual
(
len
(
chapter
.
children
),
2
)
sequential
=
chapter
.
children
[
0
]
self
.
visit_sequential
(
course
,
chapter
,
sequential
)
# remove all sequentials from chapter
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
,
course
.
id
):
for
sequential
in
chapter
.
children
:
self
.
store
.
delete_item
(
sequential
.
location
,
self
.
user
.
id
)
# pylint: disable=no-member
# check resume course buttons
response
=
self
.
client
.
get
(
course_home_url
(
course
))
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertContains
(
response
,
'
Start Course
'
,
count
=
0
)
self
.
assertContains
(
response
,
'
Resume Course
'
,
count
=
1
)
class
TestCourseOutlinePreview
(
SharedModuleStoreTestCase
):
...
...
@@ -184,8 +297,8 @@ class TestCourseOutlinePreview(SharedModuleStoreTestCase):
self
.
assertEqual
(
response
.
status_code
,
200
)
return
response
# TODO: LEARNER-837:
If you see this past 6/4/2017, please see why ticket is not yet closed
.
@skip
(
"
testing
skipping
"
)
# TODO: LEARNER-837:
Due 6/4/2017. Remove skip
.
@skip
(
"
skipping
test
"
)
def
test_preview
(
self
):
"""
Verify the behavior of preview for the course outline.
...
...
@@ -203,16 +316,16 @@ class TestCourseOutlinePreview(SharedModuleStoreTestCase):
parent_location
=
course
.
location
,
display_name
=
'
First Chapter
'
,
)
se
ction
=
ItemFactory
.
create
(
category
=
'
sequential
'
,
parent_location
=
chapter
.
location
)
ItemFactory
.
create
(
category
=
'
vertical
'
,
parent_location
=
se
ction
.
location
)
se
quential
=
ItemFactory
.
create
(
category
=
'
sequential
'
,
parent_location
=
chapter
.
location
)
ItemFactory
.
create
(
category
=
'
vertical
'
,
parent_location
=
se
quential
.
location
)
chapter
=
ItemFactory
.
create
(
category
=
'
chapter
'
,
parent_location
=
course
.
location
,
display_name
=
'
Future Chapter
'
,
due
=
future_date
,
)
se
ction
=
ItemFactory
.
create
(
category
=
'
sequential
'
,
parent_location
=
chapter
.
location
)
ItemFactory
.
create
(
category
=
'
vertical
'
,
parent_location
=
se
ction
.
location
)
se
quential
=
ItemFactory
.
create
(
category
=
'
sequential
'
,
parent_location
=
chapter
.
location
)
ItemFactory
.
create
(
category
=
'
vertical
'
,
parent_location
=
se
quential
.
location
)
# Verify that a staff user sees a chapter with a due date in the future
self
.
client
.
login
(
username
=
staff_user
.
username
,
password
=
'
test
'
)
...
...
This diff is collapsed.
Click to expand it.
openedx/features/course_experience/utils.py
+
7
−
7
View file @
8569cb35
...
...
@@ -32,15 +32,15 @@ def get_course_outline_block_tree(request, course_id):
return
block
def
set_last
ed
_accessed_default
(
block
):
def
set_last_accessed_default
(
block
):
"""
Set default of False for last_accessed on all blocks.
"""
block
[
'
last_accessed
'
]
=
False
for
child
in
block
.
get
(
'
children
'
,
[]):
set_last
ed
_accessed_default
(
child
)
set_last_accessed_default
(
child
)
def
mark_last
ed
_accessed
(
user
,
course_key
,
block
):
def
mark_last_accessed
(
user
,
course_key
,
block
):
"""
Recursively marks the branch to the last accessed block.
"""
...
...
@@ -49,10 +49,10 @@ def get_course_outline_block_tree(request, course_id):
last_accessed_child_position
=
student_module_dict
.
get
(
'
position
'
)
if
last_accessed_child_position
and
block
.
get
(
'
children
'
):
block
[
'
last_accessed
'
]
=
True
if
len
(
block
[
'
children
'
])
<=
last_accessed_child_position
:
if
last_accessed_child_position
<=
len
(
block
[
'
children
'
])
:
last_accessed_child_block
=
block
[
'
children
'
][
last_accessed_child_position
-
1
]
last_accessed_child_block
[
'
last_accessed
'
]
=
True
mark_last
ed
_accessed
(
user
,
course_key
,
last_accessed_child_block
)
mark_last_accessed
(
user
,
course_key
,
last_accessed_child_block
)
else
:
# We should be using an id in place of position for last accessed. However, while using position, if
# the child block is no longer accessible we'll use the last child.
...
...
@@ -72,7 +72,7 @@ def get_course_outline_block_tree(request, course_id):
course_outline_root_block
=
all_blocks
[
'
blocks
'
][
all_blocks
[
'
root
'
]]
populate_children
(
course_outline_root_block
,
all_blocks
[
'
blocks
'
])
set_last
ed
_accessed_default
(
course_outline_root_block
)
mark_last
ed
_accessed
(
request
.
user
,
course_key
,
course_outline_root_block
)
set_last_accessed_default
(
course_outline_root_block
)
mark_last_accessed
(
request
.
user
,
course_key
,
course_outline_root_block
)
return
course_outline_root_block
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment