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
83eda6ac
Commit
83eda6ac
authored
Mar 26, 2013
by
cahrens
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into bug/christina/studio
parents
69c95ca7
83c0feb8
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
156 additions
and
20 deletions
+156
-20
cms/djangoapps/contentstore/tests/test_contentstore.py
+31
-3
common/lib/capa/capa/templates/choicegroup.html
+4
-2
common/lib/xmodule/xmodule/modulestore/mongo.py
+3
-0
lms/djangoapps/courseware/features/problems.feature
+4
-0
lms/djangoapps/courseware/features/problems.py
+114
-15
No files found.
cms/djangoapps/contentstore/tests/test_contentstore.py
View file @
83eda6ac
...
...
@@ -37,6 +37,14 @@ TEST_DATA_MODULESTORE = copy.deepcopy(settings.MODULESTORE)
TEST_DATA_MODULESTORE
[
'default'
][
'OPTIONS'
][
'fs_root'
]
=
path
(
'common/test/data'
)
TEST_DATA_MODULESTORE
[
'direct'
][
'OPTIONS'
][
'fs_root'
]
=
path
(
'common/test/data'
)
class
MongoCollectionFindWrapper
(
object
):
def
__init__
(
self
,
original
):
self
.
original
=
original
self
.
counter
=
0
def
find
(
self
,
query
,
*
args
,
**
kwargs
):
self
.
counter
=
self
.
counter
+
1
return
self
.
original
(
query
,
*
args
,
**
kwargs
)
@override_settings
(
MODULESTORE
=
TEST_DATA_MODULESTORE
)
class
ContentStoreToyCourseTest
(
ModuleStoreTestCase
):
...
...
@@ -145,8 +153,6 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
# make sure the parent no longer points to the child object which was deleted
self
.
assertFalse
(
sequential
.
location
.
url
()
in
chapter
.
children
)
def
test_about_overrides
(
self
):
'''
This test case verifies that a course can use specialized override for about data, e.g. /about/Fall_2012/effort.html
...
...
@@ -205,7 +211,7 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
new_loc
=
descriptor
.
location
.
_replace
(
org
=
'MITx'
,
course
=
'999'
)
print
"Checking {0} should now also be at {1}"
.
format
(
descriptor
.
location
.
url
(),
new_loc
.
url
())
resp
=
self
.
client
.
get
(
reverse
(
'edit_unit'
,
kwargs
=
{
'location'
:
new_loc
.
url
()}))
self
.
assertEqual
(
resp
.
status_code
,
200
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
def
test_delete_course
(
self
):
import_from_xml
(
modulestore
(),
'common/test/data/'
,
[
'full'
])
...
...
@@ -307,6 +313,28 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
# note, we know the link it should be because that's what in the 'full' course in the test data
self
.
assertContains
(
resp
,
'/c4x/edX/full/asset/handouts_schematic_tutorial.pdf'
)
def
test_prefetch_children
(
self
):
import_from_xml
(
modulestore
(),
'common/test/data/'
,
[
'full'
])
module_store
=
modulestore
(
'direct'
)
location
=
CourseDescriptor
.
id_to_location
(
'edX/full/6.002_Spring_2012'
)
wrapper
=
MongoCollectionFindWrapper
(
module_store
.
collection
.
find
)
module_store
.
collection
.
find
=
wrapper
.
find
course
=
module_store
.
get_item
(
location
,
depth
=
2
)
# make sure we haven't done too many round trips to DB
# note we say 4 round trips here for 1) the course, 2 & 3) for the chapters and sequentials, and
# 4) because of the RT due to calculating the inherited metadata
self
.
assertEqual
(
wrapper
.
counter
,
4
)
# make sure we pre-fetched a known sequential which should be at depth=2
self
.
assertTrue
(
Location
([
'i4x'
,
'edX'
,
'full'
,
'sequential'
,
'Administrivia_and_Circuit_Elements'
,
None
])
in
course
.
system
.
module_data
)
# make sure we don't have a specific vertical which should be at depth=3
self
.
assertFalse
(
Location
([
'i4x'
,
'edX'
,
'full'
,
'vertical'
,
'vertical_58'
,
None
])
in
course
.
system
.
module_data
)
def
test_export_course_with_unknown_metadata
(
self
):
module_store
=
modulestore
(
'direct'
)
content_store
=
contentstore
()
...
...
common/lib/capa/capa/templates/choicegroup.html
View file @
83eda6ac
...
...
@@ -17,7 +17,7 @@
% for choice_id, choice_description in choices:
<label
for=
"input_${id}_${choice_id}"
%
if
input_type =
=
'
radio
'
and
choice_id
in
value:
%
if
input_type =
=
'
radio
'
and
choice_id
=
=
value:
<%
if
status =
=
'
correct
'
:
correctness =
'correct'
...
...
@@ -32,8 +32,10 @@
% endif
>
<input
type=
"${input_type}"
name=
"input_${id}${name_array_suffix}"
id=
"input_${id}_${choice_id}"
value=
"${choice_id}"
%
if
choice_id
in
value:
%
if
input_type =
=
'
radio
'
and
choice_id =
=
value:
checked=
"true"
%
elif
input_type
!=
'
radio
'
and
choice_id
in
value:
checked=
"true"
%
endif
/>
${choice_description}
</label>
...
...
common/lib/xmodule/xmodule/modulestore/mongo.py
View file @
83eda6ac
...
...
@@ -366,6 +366,9 @@ class MongoModuleStore(ModuleStoreBase):
children
.
extend
(
item
.
get
(
'definition'
,
{})
.
get
(
'children'
,
[]))
data
[
Location
(
item
[
'location'
])]
=
item
if
depth
==
0
:
break
;
# Load all children by id. See
# http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24or
# for or-query syntax
...
...
lms/djangoapps/courseware/features/problems.feature
View file @
83eda6ac
...
...
@@ -8,6 +8,7 @@ Feature: Answer problems
And
I am viewing a
"<ProblemType>"
problem
When
I answer a
"<ProblemType>"
problem
"correctly"
Then
My
"<ProblemType>"
answer is marked
"correct"
And
The
"<ProblemType>"
problem displays a
"correct"
answer
Examples
:
|
ProblemType
|
...
...
@@ -25,6 +26,7 @@ Feature: Answer problems
And
I am viewing a
"<ProblemType>"
problem
When
I answer a
"<ProblemType>"
problem
"incorrectly"
Then
My
"<ProblemType>"
answer is marked
"incorrect"
And
The
"<ProblemType>"
problem displays a
"incorrect"
answer
Examples
:
|
ProblemType
|
...
...
@@ -41,6 +43,7 @@ Feature: Answer problems
Given
I am viewing a
"<ProblemType>"
problem
When
I check a problem
Then
My
"<ProblemType>"
answer is marked
"incorrect"
And
The
"<ProblemType>"
problem displays a
"blank"
answer
Examples
:
|
ProblemType
|
...
...
@@ -58,6 +61,7 @@ Feature: Answer problems
And
I answer a
"<ProblemType>"
problem
"<Correctness>ly"
When
I reset the problem
Then
My
"<ProblemType>"
answer is marked
"unanswered"
And
The
"<ProblemType>"
problem displays a
"blank"
answer
Examples
:
|
ProblemType
|
Correctness
|
...
...
lms/djangoapps/courseware/features/problems.py
View file @
83eda6ac
'''
Steps for problem.feature lettuce tests
'''
from
lettuce
import
world
,
step
from
lettuce.django
import
django_url
import
random
import
textwrap
import
time
from
common
import
i_am_registered_for_the_course
,
TEST_SECTION_NAME
,
section_location
from
common
import
i_am_registered_for_the_course
,
\
TEST_SECTION_NAME
,
section_location
from
capa.tests.response_xml_factory
import
OptionResponseXMLFactory
,
\
ChoiceResponseXMLFactory
,
MultipleChoiceResponseXMLFactory
,
\
StringResponseXMLFactory
,
NumericalResponseXMLFactory
,
\
...
...
@@ -26,7 +31,7 @@ PROBLEM_FACTORY_DICT = {
'kwargs'
:
{
'question_text'
:
'The correct answer is Choice 3'
,
'choices'
:
[
False
,
False
,
True
,
False
],
'choice_names'
:
[
'choice_
1'
,
'choice_2'
,
'choice_3'
,
'choice_4
'
]}},
'choice_names'
:
[
'choice_
0'
,
'choice_1'
,
'choice_2'
,
'choice_3
'
]}},
'checkbox'
:
{
'factory'
:
ChoiceResponseXMLFactory
(),
...
...
@@ -88,6 +93,9 @@ PROBLEM_FACTORY_DICT = {
def
add_problem_to_course
(
course
,
problem_type
):
'''
Add a problem to the course we have created using factories.
'''
assert
(
problem_type
in
PROBLEM_FACTORY_DICT
)
...
...
@@ -98,11 +106,12 @@ def add_problem_to_course(course, problem_type):
# Create a problem item using our generated XML
# We set rerandomize=always in the metadata so that the "Reset" button
# will appear.
problem_item
=
world
.
ItemFactory
.
create
(
parent_location
=
section_location
(
course
),
template
=
"i4x://edx/templates/problem/Blank_Common_Problem"
,
display_name
=
str
(
problem_type
),
data
=
problem_xml
,
metadata
=
{
'rerandomize'
:
'always'
})
template_name
=
"i4x://edx/templates/problem/Blank_Common_Problem"
world
.
ItemFactory
.
create
(
parent_location
=
section_location
(
course
),
template
=
template_name
,
display_name
=
str
(
problem_type
),
data
=
problem_xml
,
metadata
=
{
'rerandomize'
:
'always'
})
@step
(
u'I am viewing a "([^"]*)" problem'
)
...
...
@@ -152,9 +161,9 @@ def answer_problem(step, problem_type, correctness):
elif
problem_type
==
"multiple choice"
:
if
correctness
==
'correct'
:
inputfield
(
'multiple choice'
,
choice
=
'choice_3'
)
.
check
()
else
:
inputfield
(
'multiple choice'
,
choice
=
'choice_2'
)
.
check
()
else
:
inputfield
(
'multiple choice'
,
choice
=
'choice_1'
)
.
check
()
elif
problem_type
==
"checkbox"
:
if
correctness
==
'correct'
:
...
...
@@ -164,11 +173,13 @@ def answer_problem(step, problem_type, correctness):
inputfield
(
'checkbox'
,
choice
=
'choice_3'
)
.
check
()
elif
problem_type
==
'string'
:
textvalue
=
'correct string'
if
correctness
==
'correct'
else
'incorrect'
textvalue
=
'correct string'
if
correctness
==
'correct'
\
else
'incorrect'
inputfield
(
'string'
)
.
fill
(
textvalue
)
elif
problem_type
==
'numerical'
:
textvalue
=
"pi + 1"
if
correctness
==
'correct'
else
str
(
random
.
randint
(
-
2
,
2
))
textvalue
=
"pi + 1"
if
correctness
==
'correct'
\
else
str
(
random
.
randint
(
-
2
,
2
))
inputfield
(
'numerical'
)
.
fill
(
textvalue
)
elif
problem_type
==
'formula'
:
...
...
@@ -203,6 +214,67 @@ def answer_problem(step, problem_type, correctness):
check_problem
(
step
)
@step
(
u'The "([^"]*)" problem displays a "([^"]*)" answer'
)
def
assert_problem_has_answer
(
step
,
problem_type
,
answer_class
):
'''
Assert that the problem is displaying a particular answer.
These correspond to the same correct/incorrect
answers we set in answer_problem()
We can also check that a problem has been left blank
by setting answer_class='blank'
'''
assert
answer_class
in
[
'correct'
,
'incorrect'
,
'blank'
]
if
problem_type
==
"drop down"
:
if
answer_class
==
'blank'
:
assert
world
.
browser
.
is_element_not_present_by_css
(
'option[selected="true"]'
)
else
:
actual
=
world
.
browser
.
find_by_css
(
'option[selected="true"]'
)
.
value
expected
=
'Option 2'
if
answer_class
==
'correct'
else
'Option 3'
assert
actual
==
expected
elif
problem_type
==
"multiple choice"
:
if
answer_class
==
'correct'
:
assert_checked
(
'multiple choice'
,
[
'choice_2'
])
elif
answer_class
==
'incorrect'
:
assert_checked
(
'multiple choice'
,
[
'choice_1'
])
else
:
assert_checked
(
'multiple choice'
,
[])
elif
problem_type
==
"checkbox"
:
if
answer_class
==
'correct'
:
assert_checked
(
'checkbox'
,
[
'choice_0'
,
'choice_2'
])
elif
answer_class
==
'incorrect'
:
assert_checked
(
'checkbox'
,
[
'choice_3'
])
else
:
assert_checked
(
'checkbox'
,
[])
elif
problem_type
==
'string'
:
if
answer_class
==
'blank'
:
expected
=
''
else
:
expected
=
'correct string'
if
answer_class
==
'correct'
\
else
'incorrect'
assert_textfield
(
'string'
,
expected
)
elif
problem_type
==
'formula'
:
if
answer_class
==
'blank'
:
expected
=
''
else
:
expected
=
"x^2+2*x+y"
if
answer_class
==
'correct'
else
'x^2'
assert_textfield
(
'formula'
,
expected
)
else
:
# The other response types use random data,
# which would be difficult to check
# We trade input value coverage in the other tests for
# input type coverage in this test.
pass
@step
(
u'I check a problem'
)
def
check_problem
(
step
):
world
.
css_click
(
"input.check"
)
...
...
@@ -227,7 +299,7 @@ CORRECTNESS_SELECTORS = {
'string'
:
[
'div.correct'
],
'numerical'
:
[
'div.correct'
],
'formula'
:
[
'div.correct'
],
'script'
:
[
'div.correct'
],
'script'
:
[
'div.correct'
],
'code'
:
[
'span.correct'
]},
'incorrect'
:
{
'drop down'
:
[
'span.incorrect'
],
...
...
@@ -247,12 +319,14 @@ CORRECTNESS_SELECTORS = {
'numerical'
:
[
'div.unanswered'
],
'formula'
:
[
'div.unanswered'
],
'script'
:
[
'div.unanswered'
],
'code'
:
[
'span.unanswered'
]
}}
'code'
:
[
'span.unanswered'
]}}
@step
(
u'My "([^"]*)" answer is marked "([^"]*)"'
)
def
assert_answer_mark
(
step
,
problem_type
,
correctness
):
""" Assert that the expected answer mark is visible for a given problem type.
"""
Assert that the expected answer mark is visible
for a given problem type.
*problem_type* is a string identifying the type of problem (e.g. 'drop down')
*correctness* is in ['correct', 'incorrect', 'unanswered']
...
...
@@ -274,6 +348,7 @@ def assert_answer_mark(step, problem_type, correctness):
# Expect that we found the expected selector
assert
(
has_expected
)
def
inputfield
(
problem_type
,
choice
=
None
,
input_num
=
1
):
""" Return the <input> element for *problem_type*.
For example, if problem_type is 'string', return
...
...
@@ -289,8 +364,32 @@ def inputfield(problem_type, choice=None, input_num=1):
base
=
"_choice_"
if
problem_type
==
"multiple choice"
else
"_"
sel
=
sel
+
base
+
str
(
choice
)
# If the input element doesn't exist, fail immediately
assert
(
world
.
browser
.
is_element_present_by_css
(
sel
,
wait_time
=
4
))
# Retrieve the input element
return
world
.
browser
.
find_by_css
(
sel
)
def
assert_checked
(
problem_type
,
choices
):
'''
Assert that choice names given in *choices* are the only
ones checked.
Works for both radio and checkbox problems
'''
all_choices
=
[
'choice_0'
,
'choice_1'
,
'choice_2'
,
'choice_3'
]
for
this_choice
in
all_choices
:
element
=
inputfield
(
problem_type
,
choice
=
this_choice
)
if
this_choice
in
choices
:
assert
element
.
checked
else
:
assert
not
element
.
checked
def
assert_textfield
(
problem_type
,
expected_text
,
input_num
=
1
):
element
=
inputfield
(
problem_type
,
input_num
=
input_num
)
assert
element
.
value
==
expected_text
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