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
f6731342
Commit
f6731342
authored
Dec 13, 2013
by
Calen Pennington
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make Studio load XBlock fragment js and css on the client-side
[LMS-1421][LMS-1517]
parent
49217ebe
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
194 additions
and
64 deletions
+194
-64
cms/djangoapps/contentstore/tests/test_contentstore.py
+6
-3
cms/djangoapps/contentstore/tests/utils.py
+7
-0
cms/djangoapps/contentstore/views/item.py
+53
-21
cms/djangoapps/contentstore/views/preview.py
+7
-5
cms/static/coffee/spec/views/module_edit_spec.coffee
+53
-4
cms/static/coffee/src/views/module_edit.coffee
+31
-3
cms/static/sass/elements/_xmodules.scss
+1
-1
cms/static/sass/views/_static-pages.scss
+3
-3
cms/static/sass/views/_unit.scss
+1
-1
common/static/coffee/spec/xblock/core_spec.coffee
+11
-8
common/static/coffee/spec/xblock/runtime.v1_spec.coffee
+2
-4
lms/lib/xblock/test/test_runtime.py
+19
-11
No files found.
cms/djangoapps/contentstore/tests/test_contentstore.py
View file @
f6731342
#pylint: disable=E1101
import
shutil
import
json
import
mock
import
shutil
from
textwrap
import
dedent
...
...
@@ -503,7 +504,9 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
This verifies that a video caption url is as we expect it to be
"""
resp
=
self
.
_test_preview
(
Location
(
'i4x'
,
'edX'
,
'toy'
,
'video'
,
'sample_video'
,
None
))
self
.
assertContains
(
resp
,
'data-caption-asset-path="/c4x/edX/toy/asset/subs_"'
)
self
.
assertEquals
(
resp
.
status_code
,
200
)
content
=
json
.
loads
(
resp
.
content
)
self
.
assertIn
(
'data-caption-asset-path="/c4x/edX/toy/asset/subs_"'
,
content
[
'html'
])
def
_test_preview
(
self
,
location
):
""" Preview test case. """
...
...
@@ -514,7 +517,7 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
locator
=
loc_mapper
()
.
translate_location
(
course_items
[
0
]
.
location
.
course_id
,
location
,
True
,
True
)
resp
=
self
.
client
.
get_
html
(
locator
.
url_reverse
(
'xblock'
))
resp
=
self
.
client
.
get_
fragment
(
locator
.
url_reverse
(
'xblock'
))
self
.
assertEqual
(
resp
.
status_code
,
200
)
# TODO: uncomment when preview no longer has locations being returned.
# _test_no_locations(self, resp)
...
...
cms/djangoapps/contentstore/tests/utils.py
View file @
f6731342
...
...
@@ -57,6 +57,13 @@ class AjaxEnabledTestClient(Client):
"""
return
self
.
get
(
path
,
data
or
{},
follow
,
HTTP_ACCEPT
=
"application/json"
,
**
extra
)
def
get_fragment
(
self
,
path
,
data
=
None
,
follow
=
False
,
**
extra
):
"""
Convenience method for client.get which sets the accept type to application/x-fragment+json
"""
return
self
.
get
(
path
,
data
or
{},
follow
,
HTTP_ACCEPT
=
"application/x-fragment+json"
,
**
extra
)
@override_settings
(
MODULESTORE
=
TEST_MODULESTORE
)
class
CourseTestCase
(
ModuleStoreTestCase
):
...
...
cms/djangoapps/contentstore/views/item.py
View file @
f6731342
"""Views for items (modules)."""
import
hashlib
import
logging
from
uuid
import
uuid4
from
collections
import
OrderedDict
from
functools
import
partial
from
static_replace
import
replace_static_urls
from
xmodule_modifiers
import
wrap_xblock
from
django.conf
import
settings
from
django.core.exceptions
import
PermissionDenied
from
django.contrib.auth.decorators
import
login_required
from
django.http
import
HttpResponseBadRequest
from
django.http
import
HttpResponseBadRequest
,
HttpResponse
from
django.utils.translation
import
ugettext
as
_
from
django.views.decorators.http
import
require_http_methods
from
xblock.fields
import
Scope
from
xblock.fragment
import
Fragment
from
xblock.core
import
XBlock
import
xmodule.x_module
from
xmodule.modulestore.django
import
modulestore
,
loc_mapper
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
,
InvalidLocationError
from
xmodule.modulestore.inheritance
import
own_metadata
from
xmodule.modulestore.locator
import
BlockUsageLocator
from
xmodule.modulestore
import
Location
from
xmodule.x_module
import
prefer_xmodules
from
util.json_request
import
expect_json
,
JsonResponse
from
util.string_utils
import
str_to_bool
...
...
@@ -32,8 +36,8 @@ from ..utils import get_modulestore
from
.access
import
has_course_access
from
.helpers
import
_xmodule_recurse
from
preview
import
handler_prefix
,
get_preview_html
from
edxmako.shortcuts
import
render_to_
response
,
render_to_
string
from
contentstore.views.preview
import
get_preview_fragment
from
edxmako.shortcuts
import
render_to_string
from
models.settings.course_grading
import
CourseGradingModel
from
cms.lib.xblock.runtime
import
handler_url
...
...
@@ -50,6 +54,16 @@ CREATE_IF_NOT_FOUND = ['course_info']
xmodule
.
x_module
.
descriptor_global_handler_url
=
handler_url
def
hash_resource
(
resource
):
"""
Hash a :class:`xblock.fragment.FragmentResource
"""
md5
=
hashlib
.
md5
()
for
data
in
resource
:
md5
.
update
(
data
)
return
md5
.
hexdigest
()
# pylint: disable=unused-argument
@require_http_methods
((
"DELETE"
,
"GET"
,
"PUT"
,
"POST"
))
@login_required
...
...
@@ -95,34 +109,52 @@ def xblock_handler(request, tag=None, package_id=None, branch=None, version_guid
old_location
=
loc_mapper
()
.
translate_locator_to_location
(
locator
)
if
request
.
method
==
'GET'
:
if
'application/json'
in
request
.
META
.
get
(
'HTTP_ACCEPT'
,
'application/json'
):
fields
=
request
.
REQUEST
.
get
(
'fields'
,
''
)
.
split
(
','
)
if
'graderType'
in
fields
:
# right now can't combine output of this w/ output of _get_module_info, but worthy goal
return
JsonResponse
(
CourseGradingModel
.
get_section_grader_type
(
locator
))
# TODO: pass fields to _get_module_info and only return those
rsp
=
_get_module_info
(
locator
)
return
JsonResponse
(
rsp
)
else
:
accept_header
=
request
.
META
.
get
(
'HTTP_ACCEPT'
,
'application/json'
)
if
'application/x-fragment+json'
in
accept_header
:
component
=
modulestore
()
.
get_item
(
old_location
)
# Wrap the generated fragment in the xmodule_editor div so that the javascript
# can bind to it correctly
component
.
runtime
.
wrappers
.
append
(
partial
(
wrap_xblock
,
handler_prefix
))
component
.
runtime
.
wrappers
.
append
(
partial
(
wrap_xblock
,
'StudioRuntime'
))
try
:
content
=
component
.
render
(
'studio_view'
)
.
content
editor_fragment
=
component
.
render
(
'studio_view'
)
# catch exceptions indiscriminately, since after this point they escape the
# dungeon and surface as uneditable, unsaveable, and undeletable
# component-goblins.
except
Exception
as
exc
:
# pylint: disable=W0703
log
.
debug
(
"Unable to render studio_view for
%
r"
,
component
,
exc_info
=
True
)
content
=
render_to_string
(
'html_error.html'
,
{
'message'
:
str
(
exc
)}
)
editor_fragment
=
Fragment
(
render_to_string
(
'html_error.html'
,
{
'message'
:
str
(
exc
)})
)
return
render_to_response
(
'component.html'
,
{
'preview'
:
get_preview_html
(
request
,
component
),
'editor'
:
content
,
'label'
:
component
.
display_name
or
component
.
category
,
modulestore
()
.
save_xmodule
(
component
)
preview_fragment
=
get_preview_fragment
(
request
,
component
)
hashed_resources
=
OrderedDict
()
for
resource
in
editor_fragment
.
resources
+
preview_fragment
.
resources
:
hashed_resources
[
hash_resource
(
resource
)]
=
resource
return
JsonResponse
({
'html'
:
render_to_string
(
'component.html'
,
{
'preview'
:
preview_fragment
.
content
,
'editor'
:
editor_fragment
.
content
,
'label'
:
component
.
display_name
or
component
.
scope_ids
.
block_type
,
}),
'resources'
:
hashed_resources
.
items
()
})
elif
'application/json'
in
accept_header
:
fields
=
request
.
REQUEST
.
get
(
'fields'
,
''
)
.
split
(
','
)
if
'graderType'
in
fields
:
# right now can't combine output of this w/ output of _get_module_info, but worthy goal
return
JsonResponse
(
CourseGradingModel
.
get_section_grader_type
(
locator
))
# TODO: pass fields to _get_module_info and only return those
rsp
=
_get_module_info
(
locator
)
return
JsonResponse
(
rsp
)
else
:
return
HttpResponse
(
status
=
406
)
elif
request
.
method
==
'DELETE'
:
delete_children
=
str_to_bool
(
request
.
REQUEST
.
get
(
'recurse'
,
'False'
))
delete_all_versions
=
str_to_bool
(
request
.
REQUEST
.
get
(
'all_versions'
,
'False'
))
...
...
@@ -288,7 +320,7 @@ def _create_item(request):
data
=
None
template_id
=
request
.
json
.
get
(
'boilerplate'
)
if
template_id
is
not
None
:
clz
=
XBlock
.
load_class
(
category
,
select
=
prefer_xmodules
)
clz
=
parent
.
runtime
.
load_block_type
(
category
)
if
clz
is
not
None
:
template
=
clz
.
get_template
(
template_id
)
if
template
is
not
None
:
...
...
cms/djangoapps/contentstore/views/preview.py
View file @
f6731342
import
logging
import
hashlib
from
functools
import
partial
from
django.conf
import
settings
from
django.core.urlresolvers
import
reverse
from
django.http
import
Http404
,
HttpResponseBadRequest
from
django.contrib.auth.decorators
import
login_required
from
edxmako.shortcuts
import
render_to_
response
,
render_to_
string
from
edxmako.shortcuts
import
render_to_string
from
xmodule_modifiers
import
replace_static_urls
,
wrap_xblock
from
xmodule.error_module
import
ErrorDescriptor
...
...
@@ -15,6 +16,7 @@ from xmodule.x_module import ModuleSystem
from
xblock.runtime
import
KvsFieldData
from
xblock.django.request
import
webob_to_django_response
,
django_to_webob_request
from
xblock.exceptions
import
NoSuchHandlerError
from
xblock.fragment
import
Fragment
from
lms.lib.xblock.field_data
import
LmsFieldData
from
lms.lib.xblock.runtime
import
quote_slashes
,
unquote_slashes
...
...
@@ -143,15 +145,15 @@ def _load_preview_module(request, descriptor):
return
descriptor
def
get_preview_
html
(
request
,
descriptor
):
def
get_preview_
fragment
(
request
,
descriptor
):
"""
Returns the HTML returned by the XModule's student_view,
specified by the descriptor and idx.
"""
module
=
_load_preview_module
(
request
,
descriptor
)
try
:
content
=
module
.
render
(
"student_view"
)
.
content
fragment
=
module
.
render
(
"student_view"
)
except
Exception
as
exc
:
# pylint: disable=W0703
log
.
debug
(
"Unable to render student_view for
%
r"
,
module
,
exc_info
=
True
)
content
=
render_to_string
(
'html_error.html'
,
{
'message'
:
str
(
exc
)}
)
return
cont
ent
fragment
=
Fragment
(
render_to_string
(
'html_error.html'
,
{
'message'
:
str
(
exc
)})
)
return
fragm
ent
cms/static/coffee/spec/views/module_edit_spec.coffee
View file @
f6731342
define
[
"
coffee/src/views/module_edit"
,
"js/models/module_info"
,
"xmodule"
],
(
ModuleEdit
,
ModuleModel
)
->
define
[
"
jquery"
,
"coffee/src/views/module_edit"
,
"js/models/module_info"
,
"xmodule"
],
(
$
,
ModuleEdit
,
ModuleModel
)
->
describe
"ModuleEdit"
,
->
beforeEach
->
...
...
@@ -24,7 +24,7 @@ define ["coffee/src/views/module_edit", "js/models/module_info", "xmodule"], (Mo
</section>
</li>
"""
spyOn
(
$
.
fn
,
'load
'
).
andReturn
(
@
moduleData
)
spyOn
(
$
,
'ajax
'
).
andReturn
(
@
moduleData
)
@
moduleEdit
=
new
ModuleEdit
(
el
:
$
(
".component"
)
...
...
@@ -56,14 +56,63 @@ define ["coffee/src/views/module_edit", "js/models/module_info", "xmodule"], (Mo
beforeEach
->
spyOn
(
@
moduleEdit
,
'loadDisplay'
)
spyOn
(
@
moduleEdit
,
'delegateEvents'
)
spyOn
(
$
.
fn
,
'append'
)
spyOn
(
$
,
'getScript'
)
window
.
loadedXBlockResources
=
undefined
@
moduleEdit
.
render
()
$
.
ajax
.
mostRecentCall
.
args
[
0
].
success
(
html
:
'<div>Response html</div>'
resources
:
[
[
'hash1'
,
{
kind
:
'text'
,
mimetype
:
'text/css'
,
data
:
'inline-css'
}],
[
'hash2'
,
{
kind
:
'url'
,
mimetype
:
'text/css'
,
data
:
'css-url'
}],
[
'hash3'
,
{
kind
:
'text'
,
mimetype
:
'application/javascript'
,
data
:
'inline-js'
}],
[
'hash4'
,
{
kind
:
'url'
,
mimetype
:
'application/javascript'
,
data
:
'js-url'
}],
[
'hash5'
,
{
placement
:
'head'
,
mimetype
:
'text/html'
,
data
:
'head-html'
}],
[
'hash6'
,
{
placement
:
'not-head'
,
mimetype
:
'text/html'
,
data
:
'not-head-html'
}],
]
)
it
"loads the module preview and editor via ajax on the view element"
,
->
expect
(
@
moduleEdit
.
$el
.
load
).
toHaveBeenCalledWith
(
"/xblock/
#{
@
moduleEdit
.
model
.
id
}
"
,
jasmine
.
any
(
Function
))
@
moduleEdit
.
$el
.
load
.
mostRecentCall
.
args
[
1
]()
expect
(
$
.
ajax
).
toHaveBeenCalledWith
(
url
:
"/xblock/
#{
@
moduleEdit
.
model
.
id
}
"
type
:
"GET"
headers
:
Accept
:
'application/x-fragment+json'
success
:
jasmine
.
any
(
Function
)
)
expect
(
@
moduleEdit
.
loadDisplay
).
toHaveBeenCalled
()
expect
(
@
moduleEdit
.
delegateEvents
).
toHaveBeenCalled
()
it
"loads inline css from fragments"
,
->
expect
(
$
(
'head'
).
append
).
toHaveBeenCalledWith
(
"<style type='text/css'>inline-css</style>"
)
it
"loads css urls from fragments"
,
->
expect
(
$
(
'head'
).
append
).
toHaveBeenCalledWith
(
"<link rel='stylesheet' href='css-url' type='text/css'>"
)
it
"loads inline js from fragments"
,
->
expect
(
$
(
'head'
).
append
).
toHaveBeenCalledWith
(
"<script>inline-js</script>"
)
it
"loads js urls from fragments"
,
->
expect
(
$
.
getScript
).
toHaveBeenCalledWith
(
"js-url"
)
it
"loads head html"
,
->
expect
(
$
(
'head'
).
append
).
toHaveBeenCalledWith
(
"head-html"
)
it
"doesn't load body html"
,
->
expect
(
$
.
fn
.
append
).
not
.
toHaveBeenCalledWith
(
'not-head-html'
)
it
"doesn't reload resources"
,
->
count
=
$
(
'head'
).
append
.
callCount
$
.
ajax
.
mostRecentCall
.
args
[
0
].
success
(
html
:
'<div>Response html 2</div>'
resources
:
[
[
'hash1'
,
{
kind
:
'text'
,
mimetype
:
'text/css'
,
data
:
'inline-css'
}],
]
)
expect
(
$
(
'head'
).
append
.
callCount
).
toBe
(
count
)
describe
"loadDisplay"
,
->
beforeEach
->
spyOn
(
XBlock
,
'initializeBlock'
)
...
...
cms/static/coffee/src/views/module_edit.coffee
View file @
f6731342
...
...
@@ -75,9 +75,37 @@ define ["backbone", "jquery", "underscore", "gettext", "xblock/runtime.v1",
render
:
->
if
@
model
.
id
@
$el
.
load
(
@
model
.
url
(),
=>
@
loadDisplay
()
@
delegateEvents
()
$
.
ajax
(
url
:
@
model
.
url
()
type
:
'GET'
headers
:
Accept
:
'application/x-fragment+json'
success
:
(
data
)
=>
@
$el
.
html
(
data
.
html
)
for
value
in
data
.
resources
do
(
value
)
=>
hash
=
value
[
0
]
if
not
window
.
loadedXBlockResources
?
window
.
loadedXBlockResources
=
[]
if
hash
not
in
window
.
loadedXBlockResources
resource
=
value
[
1
]
switch
resource
.
mimetype
when
"text/css"
switch
resource
.
kind
when
"text"
then
$
(
'head'
).
append
(
"<style type='text/css'>
#{
resource
.
data
}
</style>"
)
when
"url"
then
$
(
'head'
).
append
(
"<link rel='stylesheet' href='
#{
resource
.
data
}
' type='text/css'>"
)
when
"application/javascript"
switch
resource
.
kind
when
"text"
then
$
(
'head'
).
append
(
"<script>
#{
resource
.
data
}
</script>"
)
when
"url"
then
$
.
getScript
(
resource
.
data
)
when
"text/html"
switch
resource
.
placement
when
"head"
then
$
(
'head'
).
append
(
resource
.
data
)
window
.
loadedXBlockResources
.
push
(
hash
)
@
loadDisplay
()
@
delegateEvents
()
)
clickSaveButton
:
(
event
)
=>
...
...
cms/static/sass/elements/_xmodules.scss
View file @
f6731342
...
...
@@ -16,7 +16,7 @@
.xmodule_VideoModule
{
// display mode
&
.x
module_display
{
&
.x
block-student_view
{
// full screen
.video-controls
.add-fullscreen
{
...
...
cms/static/sass/views/_static-pages.scss
View file @
f6731342
...
...
@@ -183,16 +183,16 @@
border-left
:
1px
solid
$mediumGrey
;
border-right
:
1px
solid
$mediumGrey
;
.x
module_display
{
.x
block-student_view
{
display
:
none
;
}
}
.new
.x
module_display
{
.new
.x
block-student_view
{
background
:
$yellow
;
}
.x
module_display
{
.x
block-student_view
{
@include
transition
(
background-color
$tmg-s3
linear
0s
);
padding
:
20px
20px
22px
;
font-size
:
24px
;
...
...
cms/static/sass/views/_unit.scss
View file @
f6731342
...
...
@@ -420,7 +420,7 @@ body.course.unit,.view-unit {
}
}
.x
module_display
{
.x
block-student_view
{
padding
:
2
*
$baseline
$baseline
$baseline
;
overflow-x
:
auto
;
...
...
common/static/coffee/spec/xblock/core_spec.coffee
View file @
f6731342
...
...
@@ -2,9 +2,9 @@ describe "XBlock", ->
beforeEach
->
setFixtures
"""
<div>
<div class='xblock' id='vA' data-runtime-version="A" data-init="initFnA" data-name="a-name"/>
<div class='xblock' id='vA' data-runtime-version="A" data-
runtime-class="TestRuntime" data-
init="initFnA" data-name="a-name"/>
<div>
<div class='xblock' id='vZ' data-runtime-version="Z" data-init="initFnZ"/>
<div class='xblock' id='vZ' data-runtime-version="Z" data-
runtime-class="TestRuntime" data-
init="initFnZ"/>
</div>
<div class='xblock' id='missing-version' data-init='initFnA' data-name='no-version'/>
<div class='xblock' id='missing-init' data-runtime-version="A" data-name='no-init'/>
...
...
@@ -13,8 +13,11 @@ describe "XBlock", ->
describe
"initializeBlock"
,
->
beforeEach
->
XBlock
.
runtime
.
vA
=
jasmine
.
createSpy
().
andReturn
(
'runtimeA'
)
XBlock
.
runtime
.
vZ
=
jasmine
.
createSpy
().
andReturn
(
'runtimeZ'
)
window
.
TestRuntime
=
{}
@
runtimeA
=
{
name
:
'runtimeA'
}
@
runtimeZ
=
{
name
:
'runtimeZ'
}
TestRuntime
.
vA
=
jasmine
.
createSpy
().
andReturn
(
@
runtimeA
)
TestRuntime
.
vZ
=
jasmine
.
createSpy
().
andReturn
(
@
runtimeZ
)
window
.
initFnA
=
jasmine
.
createSpy
()
window
.
initFnZ
=
jasmine
.
createSpy
()
...
...
@@ -28,12 +31,12 @@ describe "XBlock", ->
@
missingInitBlock
=
XBlock
.
initializeBlock
(
$
(
'#missing-init'
)[
0
])
it
"loads the right runtime version"
,
->
expect
(
XBlock
.
r
untime
.
vA
).
toHaveBeenCalledWith
(
$
(
'#vA'
)[
0
],
@
fakeChildren
)
expect
(
XBlock
.
r
untime
.
vZ
).
toHaveBeenCalledWith
(
$
(
'#vZ'
)[
0
],
@
fakeChildren
)
expect
(
TestR
untime
.
vA
).
toHaveBeenCalledWith
(
$
(
'#vA'
)[
0
],
@
fakeChildren
)
expect
(
TestR
untime
.
vZ
).
toHaveBeenCalledWith
(
$
(
'#vZ'
)[
0
],
@
fakeChildren
)
it
"loads the right init function"
,
->
expect
(
window
.
initFnA
).
toHaveBeenCalledWith
(
'runtimeA'
,
$
(
'#vA'
)[
0
])
expect
(
window
.
initFnZ
).
toHaveBeenCalledWith
(
'runtimeZ'
,
$
(
'#vZ'
)[
0
])
expect
(
window
.
initFnA
).
toHaveBeenCalledWith
(
@
runtimeA
,
$
(
'#vA'
)[
0
])
expect
(
window
.
initFnZ
).
toHaveBeenCalledWith
(
@
runtimeZ
,
$
(
'#vZ'
)[
0
])
it
"loads when missing versions"
,
->
expect
(
@
missingVersionBlock
.
element
).
toBe
(
$
(
'#missing-version'
))
...
...
common/static/coffee/spec/xblock/runtime.v1_spec.coffee
View file @
f6731342
describe
"XBlock.
r
untime.v1"
,
->
describe
"XBlock.
R
untime.v1"
,
->
beforeEach
->
setFixtures
"""
<div class='xblock' data-handler-prefix='/xblock/fake-usage-id/handler'/>
...
...
@@ -10,9 +10,7 @@ describe "XBlock.runtime.v1", ->
@
element
=
$
(
'.xblock'
)[
0
]
@
runtime
=
XBlock
.
runtime
.
v1
(
@
element
,
@
children
)
it
"provides a handler url"
,
->
expect
(
@
runtime
.
handlerUrl
(
@
element
,
'foo'
)).
toBe
(
'/xblock/fake-usage-id/handler/foo'
)
@
runtime
=
new
XBlock
.
Runtime
.
v1
(
@
element
,
@
children
)
it
"provides a list of children"
,
->
expect
(
@
runtime
.
children
).
toBe
(
@
children
)
...
...
lms/lib/xblock/test/test_runtime.py
View file @
f6731342
...
...
@@ -6,7 +6,7 @@ from ddt import ddt, data
from
mock
import
Mock
from
unittest
import
TestCase
from
urlparse
import
urlparse
from
lms.lib.xblock.runtime
import
quote_slashes
,
unquote_slashes
,
handler_url
from
lms.lib.xblock.runtime
import
quote_slashes
,
unquote_slashes
,
LmsModuleSystem
TEST_STRINGS
=
[
''
,
...
...
@@ -41,23 +41,31 @@ class TestHandlerUrl(TestCase):
def
setUp
(
self
):
self
.
block
=
Mock
()
self
.
course_id
=
"org/course/run"
self
.
runtime
=
LmsModuleSystem
(
static_url
=
'/static'
,
track_function
=
Mock
(),
get_module
=
Mock
(),
render_template
=
Mock
(),
replace_urls
=
str
,
course_id
=
self
.
course_id
,
)
def
test_trailing_characters
(
self
):
self
.
assertFalse
(
handler_url
(
self
.
course_id
,
self
.
block
,
'handler'
)
.
endswith
(
'?'
))
self
.
assertFalse
(
handler_url
(
self
.
course_id
,
self
.
block
,
'handler'
)
.
endswith
(
'/'
))
self
.
assertFalse
(
self
.
runtime
.
handler_url
(
self
.
block
,
'handler'
)
.
endswith
(
'?'
))
self
.
assertFalse
(
self
.
runtime
.
handler_url
(
self
.
block
,
'handler'
)
.
endswith
(
'/'
))
self
.
assertFalse
(
handler_url
(
self
.
course_id
,
self
.
block
,
'handler'
,
'suffix'
)
.
endswith
(
'?'
))
self
.
assertFalse
(
handler_url
(
self
.
course_id
,
self
.
block
,
'handler'
,
'suffix'
)
.
endswith
(
'/'
))
self
.
assertFalse
(
self
.
runtime
.
handler_url
(
self
.
block
,
'handler'
,
'suffix'
)
.
endswith
(
'?'
))
self
.
assertFalse
(
self
.
runtime
.
handler_url
(
self
.
block
,
'handler'
,
'suffix'
)
.
endswith
(
'/'
))
self
.
assertFalse
(
handler_url
(
self
.
course_id
,
self
.
block
,
'handler'
,
'suffix'
,
'query'
)
.
endswith
(
'?'
))
self
.
assertFalse
(
handler_url
(
self
.
course_id
,
self
.
block
,
'handler'
,
'suffix'
,
'query'
)
.
endswith
(
'/'
))
self
.
assertFalse
(
self
.
runtime
.
handler_url
(
self
.
block
,
'handler'
,
'suffix'
,
'query'
)
.
endswith
(
'?'
))
self
.
assertFalse
(
self
.
runtime
.
handler_url
(
self
.
block
,
'handler'
,
'suffix'
,
'query'
)
.
endswith
(
'/'
))
self
.
assertFalse
(
handler_url
(
self
.
course_id
,
self
.
block
,
'handler'
,
query
=
'query'
)
.
endswith
(
'?'
))
self
.
assertFalse
(
handler_url
(
self
.
course_id
,
self
.
block
,
'handler'
,
query
=
'query'
)
.
endswith
(
'/'
))
self
.
assertFalse
(
self
.
runtime
.
handler_url
(
self
.
block
,
'handler'
,
query
=
'query'
)
.
endswith
(
'?'
))
self
.
assertFalse
(
self
.
runtime
.
handler_url
(
self
.
block
,
'handler'
,
query
=
'query'
)
.
endswith
(
'/'
))
def
_parsed_query
(
self
,
query_string
):
"""Return the parsed query string from a handler_url generated with the supplied query_string"""
return
urlparse
(
handler_url
(
self
.
course_id
,
self
.
block
,
'handler'
,
query
=
query_string
))
.
query
return
urlparse
(
self
.
runtime
.
handler_url
(
self
.
block
,
'handler'
,
query
=
query_string
))
.
query
def
test_query_string
(
self
):
self
.
assertIn
(
'foo=bar'
,
self
.
_parsed_query
(
'foo=bar'
))
...
...
@@ -66,7 +74,7 @@ class TestHandlerUrl(TestCase):
def
_parsed_path
(
self
,
handler_name
=
'handler'
,
suffix
=
''
):
"""Return the parsed path from a handler_url with the supplied handler_name and suffix"""
return
urlparse
(
handler_url
(
self
.
course_id
,
self
.
block
,
handler_name
,
suffix
=
suffix
))
.
path
return
urlparse
(
self
.
runtime
.
handler_url
(
self
.
block
,
handler_name
,
suffix
=
suffix
))
.
path
def
test_suffix
(
self
):
self
.
assertTrue
(
self
.
_parsed_path
(
suffix
=
"foo"
)
.
endswith
(
'foo'
))
...
...
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