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
420ae2da
Commit
420ae2da
authored
Aug 21, 2014
by
Christina Roberts
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #4857 from edx/christina/stud-2093
Add bok choy tests for bad HTML module content.
parents
06842be8
49f4d1ee
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
207 additions
and
101 deletions
+207
-101
cms/static/js/views/container.js
+15
-9
cms/templates/js/mock/mock-container-xblock.underscore
+3
-3
common/test/acceptance/pages/studio/container.py
+8
-2
common/test/acceptance/tests/base_studio_test.py
+75
-1
common/test/acceptance/tests/test_studio_bad_data.py
+105
-0
common/test/acceptance/tests/test_studio_container.py
+1
-86
No files found.
cms/static/js/views/container.js
View file @
420ae2da
define
([
"jquery"
,
"underscore"
,
"js/views/xblock"
,
"js/utils/module"
,
"gettext"
,
"js/views/feedback_notification"
,
"jquery.ui"
],
// The container view uses sortable, which is provided by jquery.ui.
function
(
$
,
_
,
XBlockView
,
ModuleUtils
,
gettext
,
NotificationView
)
{
var
reorderableClass
=
'.reorderable-container'
,
sortableInitializedClass
=
'.ui-sortable'
,
studioXBlockWrapperClass
=
'.studio-xblock-wrapper'
;
var
studioXBlockWrapperClass
=
'.studio-xblock-wrapper'
;
var
ContainerView
=
XBlockView
.
extend
({
// Store the request token of the first xblock on the page (which we know was rendered by Studio when
// the page was generated). Use that request token to filter out user-defined HTML in any
// child xblocks within the page.
requestToken
:
""
,
xblockReady
:
function
()
{
XBlockView
.
prototype
.
xblockReady
.
call
(
this
);
var
reorderableContainer
=
this
.
$
(
reorderableClass
),
alreadySortable
=
this
.
$
(
sortableInitializedClass
),
newParent
,
oldParent
,
self
=
this
;
var
reorderableClass
,
reorderableContainer
,
newParent
,
oldParent
,
self
=
this
;
alreadySortable
.
sortable
(
"destroy"
);
this
.
requestToken
=
this
.
$
(
'div.xblock'
).
first
().
data
(
'request-token'
);
reorderableClass
=
this
.
makeRequestSpecificSelector
(
'.reorderable-container'
);
reorderableContainer
=
this
.
$
(
reorderableClass
);
reorderableContainer
.
sortable
({
handle
:
'.drag-handle'
,
...
...
@@ -123,7 +124,12 @@ define(["jquery", "underscore", "js/views/xblock", "js/utils/module", "gettext",
},
refresh
:
function
()
{
var
sortableInitializedClass
=
this
.
makeRequestSpecificSelector
(
'.reorderable-container.ui-sortable'
);
this
.
$
(
sortableInitializedClass
).
sortable
(
'refresh'
);
},
makeRequestSpecificSelector
:
function
(
selector
)
{
return
'div.xblock[data-request-token="'
+
this
.
requestToken
+
'"] > '
+
selector
;
}
});
...
...
cms/templates/js/mock/mock-container-xblock.underscore
View file @
420ae2da
...
...
@@ -10,7 +10,7 @@
</div>
</header>
<article class="xblock-render">
<div class="xblock" data-locator="locator-container"
<div class="xblock" data-locator="locator-container"
data-request-token="page-render-token"
data-init="MockXBlock" data-runtime-class="StudioRuntime" data-runtime-version="1">
<ol class="reorderable-container">
<li class="studio-xblock-wrapper is-draggable" data-locator="locator-group-A">
...
...
@@ -35,7 +35,7 @@
</header>
<article class="xblock-render">
<div class="xblock">
<div class="xblock"
data-request-token="page-render-token"
>
<ol class="reorderable-container">
<li class="studio-xblock-wrapper is-draggable" data-locator="locator-component-A1">
<section class="wrapper-xblock level-element"
...
...
@@ -144,7 +144,7 @@
</header>
<article class="xblock-render">
<div class="xblock">
<div class="xblock"
data-request-token="page-render-token"
>
<ol class="reorderable-container">
<li class="studio-xblock-wrapper is-draggable" data-locator="locator-component-B1">
<section class="wrapper-xblock level-element"
...
...
common/test/acceptance/pages/studio/container.py
View file @
420ae2da
...
...
@@ -39,11 +39,17 @@ class ContainerPage(PageObject):
def
is_browser_on_page
(
self
):
def
_is_finished_loading
():
is_done
=
False
# Get the request token of the first xblock rendered on the page and assume it is correct.
data_request_elements
=
self
.
q
(
css
=
'[data-request-token]'
)
if
len
(
data_request_elements
)
>
0
:
request_token
=
data_request_elements
.
first
.
attrs
(
'data-request-token'
)[
0
]
# Then find the number of Studio xblock wrappers on the page with that request token.
num_wrappers
=
len
(
self
.
q
(
css
=
'{} [data-request-token="{}"]'
.
format
(
XBlockWrapper
.
BODY_SELECTOR
,
request_token
))
.
results
)
# Wait until all components have been loaded.
# See common/static/coffee/src/xblock/core.coffee which adds the
# class "xblock-initialized" at the end of initializeBlock
num_wrappers
=
len
(
self
.
q
(
css
=
XBlockWrapper
.
BODY_SELECTOR
)
.
results
)
num_xblocks_init
=
len
(
self
.
q
(
css
=
'{} .xblock.xblock-initialized'
.
format
(
XBlockWrapper
.
BODY_SELECTOR
))
.
results
)
num_xblocks_init
=
len
(
self
.
q
(
css
=
'{} .xblock.xblock-initialized[data-request-token="{}"]'
.
format
(
XBlockWrapper
.
BODY_SELECTOR
,
request_token
))
.
results
)
is_done
=
num_wrappers
==
num_xblocks_init
return
(
is_done
,
is_done
)
...
...
common/test/acceptance/tests/base_studio_test.py
View file @
420ae2da
from
..pages.studio.auto_auth
import
AutoAuthPage
from
..fixtures.course
import
CourseFixture
from
.helpers
import
UniqueCourseTest
from
..pages.studio.overview
import
CourseOutlinePage
class
StudioCourseTest
(
UniqueCourseTest
):
"""
...
...
@@ -44,3 +44,77 @@ class StudioCourseTest(UniqueCourseTest):
password
=
user
.
get
(
'password'
)
)
self
.
auth_page
.
visit
()
class
ContainerBase
(
StudioCourseTest
):
"""
Base class for tests that do operations on the container page.
"""
def
setUp
(
self
):
"""
Create a unique identifier for the course used in this test.
"""
# Ensure that the superclass sets up
super
(
ContainerBase
,
self
)
.
setUp
()
self
.
outline
=
CourseOutlinePage
(
self
.
browser
,
self
.
course_info
[
'org'
],
self
.
course_info
[
'number'
],
self
.
course_info
[
'run'
]
)
def
go_to_nested_container_page
(
self
):
"""
Go to the nested container page.
"""
unit
=
self
.
go_to_unit_page
()
# The 0th entry is the unit page itself.
container
=
unit
.
xblocks
[
1
]
.
go_to_container
()
return
container
def
go_to_unit_page
(
self
,
section_name
=
'Test Section'
,
subsection_name
=
'Test Subsection'
,
unit_name
=
'Test Unit'
):
"""
Go to the test unit page.
If make_draft is true, the unit page will be put into draft mode.
"""
self
.
outline
.
visit
()
subsection
=
self
.
outline
.
section
(
section_name
)
.
subsection
(
subsection_name
)
return
subsection
.
toggle_expand
()
.
unit
(
unit_name
)
.
go_to
()
def
verify_ordering
(
self
,
container
,
expected_orderings
):
"""
Verifies the expected ordering of xblocks on the page.
"""
xblocks
=
container
.
xblocks
blocks_checked
=
set
()
for
expected_ordering
in
expected_orderings
:
for
xblock
in
xblocks
:
parent
=
expected_ordering
.
keys
()[
0
]
if
xblock
.
name
==
parent
:
blocks_checked
.
add
(
parent
)
children
=
xblock
.
children
expected_length
=
len
(
expected_ordering
.
get
(
parent
))
self
.
assertEqual
(
expected_length
,
len
(
children
),
"Number of children incorrect for group {0}. Expected {1} but got {2}."
.
format
(
parent
,
expected_length
,
len
(
children
)))
for
idx
,
expected
in
enumerate
(
expected_ordering
.
get
(
parent
)):
self
.
assertEqual
(
expected
,
children
[
idx
]
.
name
)
blocks_checked
.
add
(
expected
)
break
self
.
assertEqual
(
len
(
blocks_checked
),
len
(
xblocks
))
def
do_action_and_verify
(
self
,
action
,
expected_ordering
):
"""
Perform the supplied action and then verify the resulting ordering.
"""
container
=
self
.
go_to_nested_container_page
()
action
(
container
)
self
.
verify_ordering
(
container
,
expected_ordering
)
# Reload the page to see that the change was persisted.
container
=
self
.
go_to_nested_container_page
()
self
.
verify_ordering
(
container
,
expected_ordering
)
common/test/acceptance/tests/test_studio_bad_data.py
0 → 100644
View file @
420ae2da
from
nose.plugins.attrib
import
attr
from
.base_studio_test
import
ContainerBase
from
..fixtures.course
import
XBlockFixtureDesc
@attr
(
'shard_1'
)
class
BadComponentTest
(
ContainerBase
):
"""
Tests that components with bad content do not break the Unit page.
"""
__test__
=
False
def
get_bad_html_content
(
self
):
"""
Return the "bad" HTML content that has been problematic for Studio.
"""
pass
def
populate_course_fixture
(
self
,
course_fixture
):
"""
Sets up a course structure with a unit and a HTML component with bad data and a properly constructed problem.
"""
course_fixture
.
add_children
(
XBlockFixtureDesc
(
'chapter'
,
'Test Section'
)
.
add_children
(
XBlockFixtureDesc
(
'sequential'
,
'Test Subsection'
)
.
add_children
(
XBlockFixtureDesc
(
'vertical'
,
'Test Unit'
)
.
add_children
(
XBlockFixtureDesc
(
'html'
,
'Unit HTML'
,
data
=
self
.
get_bad_html_content
()),
XBlockFixtureDesc
(
'problem'
,
'Unit Problem'
,
data
=
'<problem></problem>'
)
)
)
)
)
def
test_html_comp_visible
(
self
):
"""
Tests that bad HTML data within an HTML component doesn't prevent Studio from
displaying the components on the unit page.
"""
unit
=
self
.
go_to_unit_page
()
self
.
verify_ordering
(
unit
,
[{
""
:
[
"Unit HTML"
,
"Unit Problem"
]}])
@attr
(
'shard_1'
)
class
CopiedFromLmsBadContentTest
(
BadComponentTest
):
"""
Tests that components with HTML copied from the LMS (LmsRuntime) do not break the Unit page.
"""
__test__
=
True
def
get_bad_html_content
(
self
):
"""
Return the "bad" HTML content that has been problematic for Studio.
"""
return
"""
<div class="xblock xblock-student_view xmodule_display xmodule_HtmlModule xblock-initialized"
data-runtime-class="LmsRuntime" data-init="XBlockToXModuleShim" data-block-type="html"
data-runtime-version="1" data-type="HTMLModule" data-course-id="GeorgetownX/HUMW-421-01"
data-request-token="thisIsNotARealRequestToken"
data-usage-id="i4x:;_;_GeorgetownX;_HUMW-421-01;_html;_3010cbbecaa1484da6cf8ba01362346a">
<p>Copied from LMS HTML component</p></div>
"""
@attr
(
'shard_1'
)
class
CopiedFromStudioBadContentTest
(
BadComponentTest
):
"""
Tests that components with HTML copied from the Studio (containing "ui-sortable" class) do not break the Unit page.
"""
__test__
=
True
def
get_bad_html_content
(
self
):
"""
Return the "bad" HTML content that has been problematic for Studio.
"""
return
"""
<ol class="components ui-sortable">
<li class="component" data-locator="i4x://Wellesley_College/100/html/6390f1fd3fe640d49580b8415fe1330b"
data-course-key="Wellesley_College/100/2014_Summer">
<div class="xblock xblock-student_view xmodule_display xmodule_HtmlModule xblock-initialized"
data-runtime-class="PreviewRuntime" data-init="XBlockToXModuleShim" data-runtime-version="1"
data-request-token="thisIsNotARealRequestToken"
data-usage-id="i4x://Wellesley_College/100/html/6390f1fd3fe640d49580b8415fe1330b"
data-type="HTMLModule" data-block-type="html">
<h2>VOICE COMPARISON </h2>
<p>You can access the experimental <strong >Voice Comparison</strong> tool at the link below.</p>
</div>
</li>
</ol>
"""
@attr
(
'shard_1'
)
class
JSErrorBadContentTest
(
BadComponentTest
):
"""
Tests that components that throw JS errors do not break the Unit page.
"""
# TODO: ENABLE TEST WITH ANDY'S PR
__test__
=
False
def
get_bad_html_content
(
self
):
"""
Return the "bad" HTML content that has been problematic for Studio.
"""
return
"<script>var doesNotExist = BadGlobal.foo;</script>"
common/test/acceptance/tests/test_studio_container.py
View file @
420ae2da
...
...
@@ -5,8 +5,6 @@ displaying containers within units.
"""
from
nose.plugins.attrib
import
attr
from
..pages.studio.overview
import
CourseOutlinePage
from
..fixtures.course
import
XBlockFixtureDesc
from
..pages.studio.component_editor
import
ComponentEditorView
from
..pages.studio.html_component_editor
import
HtmlComponentEditorView
...
...
@@ -16,87 +14,10 @@ from ..pages.lms.staff_view import StaffPage
import
datetime
from
bok_choy.promise
import
Promise
,
EmptyPromise
from
.base_studio_test
import
StudioCourseTest
@attr
(
'shard_1'
)
class
ContainerBase
(
StudioCourseTest
):
"""
Base class for tests that do operations on the container page.
"""
__test__
=
False
def
setUp
(
self
):
"""
Create a unique identifier for the course used in this test.
"""
# Ensure that the superclass sets up
super
(
ContainerBase
,
self
)
.
setUp
()
self
.
outline
=
CourseOutlinePage
(
self
.
browser
,
self
.
course_info
[
'org'
],
self
.
course_info
[
'number'
],
self
.
course_info
[
'run'
]
)
def
go_to_nested_container_page
(
self
):
"""
Go to the nested container page.
"""
unit
=
self
.
go_to_unit_page
()
# The 0th entry is the unit page itself.
container
=
unit
.
xblocks
[
1
]
.
go_to_container
()
return
container
def
go_to_unit_page
(
self
,
section_name
=
'Test Section'
,
subsection_name
=
'Test Subsection'
,
unit_name
=
'Test Unit'
):
"""
Go to the test unit page.
If make_draft is true, the unit page will be put into draft mode.
"""
self
.
outline
.
visit
()
subsection
=
self
.
outline
.
section
(
section_name
)
.
subsection
(
subsection_name
)
return
subsection
.
toggle_expand
()
.
unit
(
unit_name
)
.
go_to
()
def
verify_ordering
(
self
,
container
,
expected_orderings
):
"""
Verifies the expected ordering of xblocks on the page.
"""
xblocks
=
container
.
xblocks
blocks_checked
=
set
()
for
expected_ordering
in
expected_orderings
:
for
xblock
in
xblocks
:
parent
=
expected_ordering
.
keys
()[
0
]
if
xblock
.
name
==
parent
:
blocks_checked
.
add
(
parent
)
children
=
xblock
.
children
expected_length
=
len
(
expected_ordering
.
get
(
parent
))
self
.
assertEqual
(
expected_length
,
len
(
children
),
"Number of children incorrect for group {0}. Expected {1} but got {2}."
.
format
(
parent
,
expected_length
,
len
(
children
)))
for
idx
,
expected
in
enumerate
(
expected_ordering
.
get
(
parent
)):
self
.
assertEqual
(
expected
,
children
[
idx
]
.
name
)
blocks_checked
.
add
(
expected
)
break
self
.
assertEqual
(
len
(
blocks_checked
),
len
(
xblocks
))
def
do_action_and_verify
(
self
,
action
,
expected_ordering
):
"""
Perform the supplied action and then verify the resulting ordering.
"""
container
=
self
.
go_to_nested_container_page
()
action
(
container
)
self
.
verify_ordering
(
container
,
expected_ordering
)
# Reload the page to see that the change was persisted.
container
=
self
.
go_to_nested_container_page
()
self
.
verify_ordering
(
container
,
expected_ordering
)
from
.base_studio_test
import
ContainerBase
class
NestedVerticalTest
(
ContainerBase
):
__test__
=
False
def
populate_course_fixture
(
self
,
course_fixture
):
"""
...
...
@@ -151,7 +72,6 @@ class DragAndDropTest(NestedVerticalTest):
"""
Tests of reordering within the container page.
"""
__test__
=
True
def
drag_and_verify
(
self
,
source
,
target
,
expected_ordering
):
self
.
do_action_and_verify
(
...
...
@@ -232,7 +152,6 @@ class AddComponentTest(NestedVerticalTest):
"""
Tests of adding a component to the container page.
"""
__test__
=
True
def
add_and_verify
(
self
,
menu_index
,
expected_ordering
):
self
.
do_action_and_verify
(
...
...
@@ -273,7 +192,6 @@ class DuplicateComponentTest(NestedVerticalTest):
"""
Tests of duplicating a component on the container page.
"""
__test__
=
True
def
duplicate_and_verify
(
self
,
source_index
,
expected_ordering
):
self
.
do_action_and_verify
(
...
...
@@ -320,7 +238,6 @@ class DeleteComponentTest(NestedVerticalTest):
"""
Tests of deleting a component from the container page.
"""
__test__
=
True
def
delete_and_verify
(
self
,
source_index
,
expected_ordering
):
self
.
do_action_and_verify
(
...
...
@@ -344,7 +261,6 @@ class EditContainerTest(NestedVerticalTest):
"""
Tests of editing a container.
"""
__test__
=
True
def
modify_display_name_and_verify
(
self
,
component
):
"""
...
...
@@ -377,7 +293,6 @@ class UnitPublishingTest(ContainerBase):
"""
Tests of the publishing control and related widgets on the Unit page.
"""
__test__
=
True
PUBLISHED_STATUS
=
"Publishing Status
\n
Published (not yet released)"
PUBLISHED_LIVE_STATUS
=
"Publishing Status
\n
Published and Live"
...
...
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