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
3d1c54fe
Commit
3d1c54fe
authored
Oct 24, 2014
by
Sarina Canelake
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #5595 from Stanford-Online/caijim/resetbutton
Support and tests for adding a reset button to units
parents
98c9880d
6d19a0c8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
426 additions
and
217 deletions
+426
-217
CHANGELOG.rst
+2
-0
cms/djangoapps/contentstore/features/problem-editor.py
+2
-0
common/lib/xmodule/xmodule/capa_base.py
+66
-54
common/lib/xmodule/xmodule/capa_base_constants.py
+28
-0
common/lib/xmodule/xmodule/modulestore/inheritance.py
+13
-2
common/lib/xmodule/xmodule/tests/test_capa_module.py
+205
-137
lms/djangoapps/courseware/features/problems.feature
+98
-24
lms/djangoapps/courseware/features/problems.py
+12
-0
No files found.
CHANGELOG.rst
View file @
3d1c54fe
...
...
@@ -5,6 +5,8 @@ These are notable changes in edx-platform. This is a rolling list of changes,
in roughly chronological order, most recent first. Add your entries at or near
the top. Include a label indicating the component affected.
Common: Add configurable reset button to units
LMS: Support adding cohorts from the instructor dashboard. TNL-162
LMS: Support adding students to a cohort via the instructor dashboard. TNL-163
...
...
cms/djangoapps/contentstore/features/problem-editor.py
View file @
3d1c54fe
...
...
@@ -13,6 +13,7 @@ MAXIMUM_ATTEMPTS = "Maximum Attempts"
PROBLEM_WEIGHT
=
"Problem Weight"
RANDOMIZATION
=
'Randomization'
SHOW_ANSWER
=
"Show Answer"
SHOW_RESET_BUTTON
=
"Show Reset Button"
TIMER_BETWEEN_ATTEMPTS
=
"Timer Between Attempts"
MATLAB_API_KEY
=
"Matlab API key"
...
...
@@ -102,6 +103,7 @@ def i_see_advanced_settings_with_values(step):
[
PROBLEM_WEIGHT
,
""
,
False
],
[
RANDOMIZATION
,
"Never"
,
False
],
[
SHOW_ANSWER
,
"Finished"
,
False
],
[
SHOW_RESET_BUTTON
,
"False"
,
False
],
[
TIMER_BETWEEN_ATTEMPTS
,
"0"
,
False
],
])
...
...
common/lib/xmodule/xmodule/capa_base.py
View file @
3d1c54fe
...
...
@@ -29,6 +29,8 @@ from xblock.fields import Scope, String, Boolean, Dict, Integer, Float
from
.fields
import
Timedelta
,
Date
from
django.utils.timezone
import
UTC
from
.util.duedate
import
get_extended_due_date
from
xmodule.capa_base_constants
import
RANDOMIZATION
,
SHOWANSWER
from
django.conf
import
settings
log
=
logging
.
getLogger
(
"edx.courseware"
)
...
...
@@ -63,9 +65,9 @@ class Randomization(String):
"""
def
from_json
(
self
,
value
):
if
value
in
(
""
,
"true"
):
return
"always"
return
RANDOMIZATION
.
ALWAYS
elif
value
==
"false"
:
return
"per_student"
return
RANDOMIZATION
.
PER_STUDENT
return
value
to_json
=
from_json
...
...
@@ -103,15 +105,15 @@ class CapaFields(object):
max_attempts
=
Integer
(
display_name
=
_
(
"Maximum Attempts"
),
help
=
_
(
"Defines the number of times a student can try to answer this problem. "
"If the value is not set, infinite attempts are allowed."
),
"If the value is not set, infinite attempts are allowed."
),
values
=
{
"min"
:
0
},
scope
=
Scope
.
settings
)
due
=
Date
(
help
=
_
(
"Date that this problem is due by"
),
scope
=
Scope
.
settings
)
extended_due
=
Date
(
help
=
_
(
"Date that this problem is due by for a particular student. This "
"can be set by an instructor, and will override the global due "
"date if it is set to a date that is later than the global due "
"date."
),
"can be set by an instructor, and will override the global due "
"date if it is set to a date that is later than the global due "
"date."
),
default
=
None
,
scope
=
Scope
.
user_state
,
)
...
...
@@ -122,36 +124,45 @@ class CapaFields(object):
showanswer
=
String
(
display_name
=
_
(
"Show Answer"
),
help
=
_
(
"Defines when to show the answer to the problem. "
"A default value can be set in Advanced Settings."
),
"A default value can be set in Advanced Settings."
),
scope
=
Scope
.
settings
,
default
=
"finished"
,
default
=
SHOWANSWER
.
FINISHED
,
values
=
[
{
"display_name"
:
_
(
"Always"
),
"value"
:
"always"
},
{
"display_name"
:
_
(
"Answered"
),
"value"
:
"answered"
},
{
"display_name"
:
_
(
"Attempted"
),
"value"
:
"attempted"
},
{
"display_name"
:
_
(
"Closed"
),
"value"
:
"closed"
},
{
"display_name"
:
_
(
"Finished"
),
"value"
:
"finished"
},
{
"display_name"
:
_
(
"Correct or Past Due"
),
"value"
:
"correct_or_past_due"
},
{
"display_name"
:
_
(
"Past Due"
),
"value"
:
"past_due"
},
{
"display_name"
:
_
(
"Never"
),
"value"
:
"never"
}]
{
"display_name"
:
_
(
"Always"
),
"value"
:
SHOWANSWER
.
ALWAYS
},
{
"display_name"
:
_
(
"Answered"
),
"value"
:
SHOWANSWER
.
ANSWERED
},
{
"display_name"
:
_
(
"Attempted"
),
"value"
:
SHOWANSWER
.
ATTEMPTED
},
{
"display_name"
:
_
(
"Closed"
),
"value"
:
SHOWANSWER
.
CLOSED
},
{
"display_name"
:
_
(
"Finished"
),
"value"
:
SHOWANSWER
.
FINISHED
},
{
"display_name"
:
_
(
"Correct or Past Due"
),
"value"
:
SHOWANSWER
.
CORRECT_OR_PAST_DUE
},
{
"display_name"
:
_
(
"Past Due"
),
"value"
:
SHOWANSWER
.
PAST_DUE
},
{
"display_name"
:
_
(
"Never"
),
"value"
:
SHOWANSWER
.
NEVER
}]
)
force_save_button
=
Boolean
(
help
=
_
(
"Whether to force the save button to appear on the page"
),
scope
=
Scope
.
settings
,
default
=
False
)
reset_key
=
"DEFAULT_SHOW_RESET_BUTTON"
default_reset_button
=
getattr
(
settings
,
reset_key
)
if
hasattr
(
settings
,
reset_key
)
else
False
show_reset_button
=
Boolean
(
display_name
=
_
(
"Show Reset Button"
),
help
=
_
(
"Determines whether a 'Reset' button is shown so the user may reset their answer. "
"A default value can be set in Advanced Settings."
),
scope
=
Scope
.
settings
,
default
=
default_reset_button
)
rerandomize
=
Randomization
(
display_name
=
_
(
"Randomization"
),
help
=
_
(
"Defines how often inputs are randomized when a student loads the problem. "
"This setting only applies to problems that can have randomly generated numeric values. "
"A default value can be set in Advanced Settings."
),
default
=
"never"
,
"This setting only applies to problems that can have randomly generated numeric values. "
"A default value can be set in Advanced Settings."
),
default
=
RANDOMIZATION
.
NEVER
,
scope
=
Scope
.
settings
,
values
=
[
{
"display_name"
:
_
(
"Always"
),
"value"
:
"always"
},
{
"display_name"
:
_
(
"On Reset"
),
"value"
:
"onreset"
},
{
"display_name"
:
_
(
"Never"
),
"value"
:
"never"
},
{
"display_name"
:
_
(
"Per Student"
),
"value"
:
"per_student"
}
{
"display_name"
:
_
(
"Always"
),
"value"
:
RANDOMIZATION
.
ALWAYS
},
{
"display_name"
:
_
(
"On Reset"
),
"value"
:
RANDOMIZATION
.
ONRESET
},
{
"display_name"
:
_
(
"Never"
),
"value"
:
RANDOMIZATION
.
NEVER
},
{
"display_name"
:
_
(
"Per Student"
),
"value"
:
RANDOMIZATION
.
PER_STUDENT
}
]
)
data
=
String
(
help
=
_
(
"XML data for the problem"
),
scope
=
Scope
.
content
,
default
=
"<problem></problem>"
)
...
...
@@ -170,7 +181,7 @@ class CapaFields(object):
weight
=
Float
(
display_name
=
_
(
"Problem Weight"
),
help
=
_
(
"Defines the number of points each problem is worth. "
"If the value is not set, each response field in the problem is worth one point."
),
"If the value is not set, each response field in the problem is worth one point."
),
values
=
{
"min"
:
0
,
"step"
:
.
1
},
scope
=
Scope
.
settings
)
...
...
@@ -254,7 +265,7 @@ class CapaMixin(CapaFields):
tb
=
cgi
.
escape
(
u''
.
join
([
'Traceback (most recent call last):
\n
'
]
+
traceback
.
format_tb
(
sys
.
exc_info
()[
2
])))
)
)
# create a dummy problem with error message instead of failing
problem_text
=
(
u'<problem><text><span class="inline-error">'
u'Problem {url} has an error:</span>{msg}</text></problem>'
.
format
(
...
...
@@ -274,9 +285,9 @@ class CapaMixin(CapaFields):
"""
Choose a new seed.
"""
if
self
.
rerandomize
==
'never'
:
if
self
.
rerandomize
==
RANDOMIZATION
.
NEVER
:
self
.
seed
=
1
elif
self
.
rerandomize
==
"per_student"
and
hasattr
(
self
.
runtime
,
'seed'
):
elif
self
.
rerandomize
==
RANDOMIZATION
.
PER_STUDENT
and
hasattr
(
self
.
runtime
,
'seed'
):
# see comment on randomization_bin
self
.
seed
=
randomization_bin
(
self
.
runtime
.
seed
,
unicode
(
self
.
location
)
.
encode
(
'utf-8'
))
else
:
...
...
@@ -446,7 +457,7 @@ class CapaMixin(CapaFields):
"""
Return True/False to indicate whether to show the "Check" button.
"""
submitted_without_reset
=
(
self
.
is_submitted
()
and
self
.
rerandomize
==
"always"
)
submitted_without_reset
=
(
self
.
is_submitted
()
and
self
.
rerandomize
==
RANDOMIZATION
.
ALWAYS
)
# If the problem is closed (past due / too many attempts)
# then we do NOT show the "check" button
...
...
@@ -463,19 +474,20 @@ class CapaMixin(CapaFields):
"""
is_survey_question
=
(
self
.
max_attempts
==
0
)
if
self
.
rerandomize
in
[
"always"
,
"onreset"
]:
# If the problem is closed (and not a survey question with max_attempts==0),
# then do NOT show the reset button.
if
(
self
.
closed
()
and
not
is_survey_question
):
return
False
# If the problem is closed (and not a survey question with max_attempts==0),
# then do NOT show the reset button.
# If the problem hasn't been submitted yet, then do NOT show
# the reset button.
if
(
self
.
closed
()
and
not
is_survey_question
)
or
not
self
.
is_submitted
():
# Button only shows up for randomized problems if the question has been submitted
if
self
.
rerandomize
in
[
RANDOMIZATION
.
ALWAYS
,
RANDOMIZATION
.
ONRESET
]
and
self
.
is_submitted
():
return
True
else
:
# Do NOT show the button if the problem is correct
if
self
.
is_correct
():
return
False
else
:
return
True
# Only randomized problems need a "reset" button
else
:
return
False
return
self
.
show_reset_button
def
should_show_save_button
(
self
):
"""
...
...
@@ -489,7 +501,7 @@ class CapaMixin(CapaFields):
return
not
self
.
closed
()
else
:
is_survey_question
=
(
self
.
max_attempts
==
0
)
needs_reset
=
self
.
is_submitted
()
and
self
.
rerandomize
==
"always"
needs_reset
=
self
.
is_submitted
()
and
self
.
rerandomize
==
RANDOMIZATION
.
ALWAYS
# If the student has unlimited attempts, and their answers
# are not randomized, then we do not need a save button
...
...
@@ -503,7 +515,7 @@ class CapaMixin(CapaFields):
# In those cases. the if statement below is false,
# and the save button can still be displayed.
#
if
self
.
max_attempts
is
None
and
self
.
rerandomize
!=
"always"
:
if
self
.
max_attempts
is
None
and
self
.
rerandomize
!=
RANDOMIZATION
.
ALWAYS
:
return
False
# If the problem is closed (and not a survey question with max_attempts==0),
...
...
@@ -697,28 +709,28 @@ class CapaMixin(CapaFields):
"""
if
self
.
showanswer
==
''
:
return
False
elif
self
.
showanswer
==
"never"
:
elif
self
.
showanswer
==
SHOWANSWER
.
NEVER
:
return
False
elif
self
.
runtime
.
user_is_staff
:
# This is after the 'never' check because admins can see the answer
# unless the problem explicitly prevents it
return
True
elif
self
.
showanswer
==
'attempted'
:
elif
self
.
showanswer
==
SHOWANSWER
.
ATTEMPTED
:
return
self
.
attempts
>
0
elif
self
.
showanswer
==
'answered'
:
elif
self
.
showanswer
==
SHOWANSWER
.
ANSWERED
:
# NOTE: this is slightly different from 'attempted' -- resetting the problems
# makes lcp.done False, but leaves attempts unchanged.
return
self
.
lcp
.
done
elif
self
.
showanswer
==
'closed'
:
elif
self
.
showanswer
==
SHOWANSWER
.
CLOSED
:
return
self
.
closed
()
elif
self
.
showanswer
==
'finished'
:
elif
self
.
showanswer
==
SHOWANSWER
.
FINISHED
:
return
self
.
closed
()
or
self
.
is_correct
()
elif
self
.
showanswer
==
'correct_or_past_due'
:
elif
self
.
showanswer
==
SHOWANSWER
.
CORRECT_OR_PAST_DUE
:
return
self
.
is_correct
()
or
self
.
is_past_due
()
elif
self
.
showanswer
==
'past_due'
:
elif
self
.
showanswer
==
SHOWANSWER
.
PAST_DUE
:
return
self
.
is_past_due
()
elif
self
.
showanswer
==
'always'
:
elif
self
.
showanswer
==
SHOWANSWER
.
ALWAYS
:
return
True
return
False
...
...
@@ -952,7 +964,7 @@ class CapaMixin(CapaFields):
raise
NotFoundError
(
_
(
"Problem is closed."
))
# Problem submitted. Student should reset before checking again
if
self
.
done
and
self
.
rerandomize
==
"always"
:
if
self
.
done
and
self
.
rerandomize
==
RANDOMIZATION
.
ALWAYS
:
event_info
[
'failure'
]
=
'unreset'
self
.
track_function_unmask
(
'problem_check_fail'
,
event_info
)
if
dog_stats_api
:
...
...
@@ -1206,7 +1218,7 @@ class CapaMixin(CapaFields):
# was presented to the user, with values interpolated etc, but that can be done
# later if necessary.
variant
=
''
if
self
.
rerandomize
!=
'never'
:
if
self
.
rerandomize
!=
RANDOMIZATION
.
NEVER
:
variant
=
self
.
seed
is_correct
=
correct_map
.
is_correct
(
input_id
)
...
...
@@ -1333,7 +1345,7 @@ class CapaMixin(CapaFields):
# Problem submitted. Student should reset before saving
# again.
if
self
.
done
and
self
.
rerandomize
==
"always"
:
if
self
.
done
and
self
.
rerandomize
==
RANDOMIZATION
.
ALWAYS
:
event_info
[
'failure'
]
=
'done'
self
.
track_function_unmask
(
'save_problem_fail'
,
event_info
)
return
{
...
...
@@ -1357,7 +1369,7 @@ class CapaMixin(CapaFields):
def
reset_problem
(
self
,
_data
):
"""
Changes problem state to unfinished -- removes student answers,
and causes problem to rerender itself
.
Causes problem to rerender itself if randomization is enabled
.
Returns a dictionary of the form:
{'success': True/False,
...
...
@@ -1380,7 +1392,7 @@ class CapaMixin(CapaFields):
'error'
:
_
(
"Problem is closed."
),
}
if
not
self
.
done
:
if
not
self
.
is_submitted
()
:
event_info
[
'failure'
]
=
'not_done'
self
.
track_function_unmask
(
'reset_problem_fail'
,
event_info
)
return
{
...
...
@@ -1389,7 +1401,7 @@ class CapaMixin(CapaFields):
'error'
:
_
(
"Refresh the page and make an attempt before resetting."
),
}
if
self
.
rerandomize
in
[
"always"
,
"onreset"
]:
if
self
.
is_submitted
()
and
self
.
rerandomize
in
[
RANDOMIZATION
.
ALWAYS
,
RANDOMIZATION
.
ONRESET
]:
# Reset random number generator seed.
self
.
choose_new_seed
()
...
...
common/lib/xmodule/xmodule/capa_base_constants.py
0 → 100644
View file @
3d1c54fe
# -*- coding: utf-8 -*-
"""
Constants for capa_base problems
"""
class
SHOWANSWER
:
"""
Constants for when to show answer
"""
ALWAYS
=
"always"
ANSWERED
=
"answered"
ATTEMPTED
=
"attempted"
CLOSED
=
"closed"
FINISHED
=
"finished"
CORRECT_OR_PAST_DUE
=
"correct_or_past_due"
PAST_DUE
=
"past_due"
NEVER
=
"never"
class
RANDOMIZATION
:
"""
Constants for problem randomization
"""
ALWAYS
=
"always"
ONRESET
=
"onreset"
NEVER
=
"never"
PER_STUDENT
=
"per_student"
common/lib/xmodule/xmodule/modulestore/inheritance.py
View file @
3d1c54fe
"""
Support for inheritance of fields down an XBlock hierarchy.
"""
from
__future__
import
absolute_import
from
datetime
import
datetime
from
pytz
import
UTC
from
xmodule.partitions.partitions
import
UserPartition
from
xblock.fields
import
Scope
,
Boolean
,
String
,
Float
,
XBlockMixin
,
Dict
,
Integer
,
List
from
xblock.runtime
import
KeyValueStore
,
KvsFieldData
from
xmodule.fields
import
Date
,
Timedelta
from
django.conf
import
settings
# Make '_' a no-op so we can scrape strings
_
=
lambda
text
:
text
...
...
@@ -153,6 +154,16 @@ class InheritanceMixin(XBlockMixin):
scope
=
Scope
.
settings
)
reset_key
=
"DEFAULT_SHOW_RESET_BUTTON"
default_reset_button
=
getattr
(
settings
,
reset_key
)
if
hasattr
(
settings
,
reset_key
)
else
False
show_reset_button
=
Boolean
(
display_name
=
_
(
"Show Reset Button for Problems"
),
help
=
_
(
"Enter true or false. If true, problems default to displaying a 'Reset' button. This value may be "
"overriden in each problem's settings. Existing problems whose reset setting have not been changed are affected."
),
scope
=
Scope
.
settings
,
default
=
default_reset_button
)
def
compute_inherited_metadata
(
descriptor
):
"""Given a descriptor, traverse all of its descendants and do metadata
...
...
common/lib/xmodule/xmodule/tests/test_capa_module.py
View file @
3d1c54fe
...
...
@@ -13,6 +13,7 @@ import random
import
os
import
textwrap
import
unittest
import
ddt
from
mock
import
Mock
,
patch
import
webob
...
...
@@ -31,6 +32,7 @@ from xblock.fields import ScopeIds
from
.
import
get_test_system
from
pytz
import
UTC
from
capa.correctmap
import
CorrectMap
from
..capa_base_constants
import
RANDOMIZATION
class
CapaFactory
(
object
):
...
...
@@ -140,7 +142,6 @@ class CapaFactory(object):
return
module
class
CapaFactoryWithFiles
(
CapaFactory
):
"""
A factory for creating a Capa problem with files attached.
...
...
@@ -182,6 +183,7 @@ if submission[0] == '':
"""
)
@ddt.ddt
class
CapaModuleTest
(
unittest
.
TestCase
):
def
setUp
(
self
):
...
...
@@ -540,39 +542,42 @@ class CapaModuleTest(unittest.TestCase):
# Expect that number of attempts NOT incremented
self
.
assertEqual
(
module
.
attempts
,
3
)
def
test_check_problem_resubmitted_with_randomize
(
self
):
rerandomize_values
=
[
'always'
,
'true'
]
for
rerandomize
in
rerandomize_values
:
# Randomize turned on
module
=
CapaFactory
.
create
(
rerandomize
=
rerandomize
,
attempts
=
0
)
@ddt.data
(
RANDOMIZATION
.
ALWAYS
,
'true'
)
def
test_check_problem_resubmitted_with_randomize
(
self
,
rerandomize
):
# Randomize turned on
module
=
CapaFactory
.
create
(
rerandomize
=
rerandomize
,
attempts
=
0
)
# Simulate that the problem is completed
module
.
done
=
True
# Expect that we cannot submit
with
self
.
assertRaises
(
xmodule
.
exceptions
.
NotFoundError
):
get_request_dict
=
{
CapaFactory
.
input_key
():
'3.14'
}
module
.
check_problem
(
get_request_dict
)
# Simulate that the problem is completed
module
.
done
=
True
# Expect that number of attempts NOT incremented
self
.
assertEqual
(
module
.
attempts
,
0
)
# Expect that we cannot submit
with
self
.
assertRaises
(
xmodule
.
exceptions
.
NotFoundError
):
get_request_dict
=
{
CapaFactory
.
input_key
():
'3.14'
}
module
.
check_problem
(
get_request_dict
)
def
test_check_problem_resubmitted_no_randomize
(
self
):
rerandomize_values
=
[
'never'
,
'false'
,
'per_student'
]
# Expect that number of attempts NOT incremented
self
.
assertEqual
(
module
.
attempts
,
0
)
for
rerandomize
in
rerandomize_values
:
# Randomize turned off
module
=
CapaFactory
.
create
(
rerandomize
=
rerandomize
,
attempts
=
0
,
done
=
True
)
@ddt.data
(
RANDOMIZATION
.
NEVER
,
'false'
,
RANDOMIZATION
.
PER_STUDENT
)
def
test_check_problem_resubmitted_no_randomize
(
self
,
rerandomize
):
# Randomize turned off
module
=
CapaFactory
.
create
(
rerandomize
=
rerandomize
,
attempts
=
0
,
done
=
True
)
# Expect that we can submit successfully
get_request_dict
=
{
CapaFactory
.
input_key
():
'3.14'
}
result
=
module
.
check_problem
(
get_request_dict
)
# Expect that we can submit successfully
get_request_dict
=
{
CapaFactory
.
input_key
():
'3.14'
}
result
=
module
.
check_problem
(
get_request_dict
)
self
.
assertEqual
(
result
[
'success'
],
'correct'
)
self
.
assertEqual
(
result
[
'success'
],
'correct'
)
# Expect that number of attempts IS incremented
self
.
assertEqual
(
module
.
attempts
,
1
)
# Expect that number of attempts IS incremented
self
.
assertEqual
(
module
.
attempts
,
1
)
def
test_check_problem_queued
(
self
):
module
=
CapaFactory
.
create
(
attempts
=
1
)
...
...
@@ -813,7 +818,7 @@ class CapaModuleTest(unittest.TestCase):
def
test_reset_problem_closed
(
self
):
# pre studio default
module
=
CapaFactory
.
create
(
rerandomize
=
"always"
)
module
=
CapaFactory
.
create
(
rerandomize
=
RANDOMIZATION
.
ALWAYS
)
# Simulate that the problem is closed
with
patch
(
'xmodule.capa_module.CapaModule.closed'
)
as
mock_closed
:
...
...
@@ -944,35 +949,36 @@ class CapaModuleTest(unittest.TestCase):
# Expect that the result is failure
self
.
assertTrue
(
'success'
in
result
and
not
result
[
'success'
])
def
test_save_problem_submitted_with_randomize
(
self
):
@ddt.data
(
RANDOMIZATION
.
ALWAYS
,
'true'
)
def
test_save_problem_submitted_with_randomize
(
self
,
rerandomize
):
# Capa XModule treats 'always' and 'true' equivalently
rerandomize_values
=
[
'always'
,
'true'
]
for
rerandomize
in
rerandomize_values
:
module
=
CapaFactory
.
create
(
rerandomize
=
rerandomize
,
done
=
True
)
module
=
CapaFactory
.
create
(
rerandomize
=
rerandomize
,
done
=
True
)
# Try to save
get_request_dict
=
{
CapaFactory
.
input_key
():
'3.14'
}
result
=
module
.
save_problem
(
get_request_dict
)
# Expect that we cannot save
self
.
assertTrue
(
'success'
in
result
and
not
result
[
'success'
])
# Try to save
get_request_dict
=
{
CapaFactory
.
input_key
():
'3.14'
}
result
=
module
.
save_problem
(
get_request_dict
)
def
test_save_problem_submitted_no_randomize
(
self
):
# Expect that we cannot save
self
.
assertTrue
(
'success'
in
result
and
not
result
[
'success'
])
@ddt.data
(
RANDOMIZATION
.
NEVER
,
'false'
,
RANDOMIZATION
.
PER_STUDENT
)
def
test_save_problem_submitted_no_randomize
(
self
,
rerandomize
):
# Capa XModule treats 'false' and 'per_student' equivalently
rerandomize_values
=
[
'never'
,
'false'
,
'per_student'
]
for
rerandomize
in
rerandomize_values
:
module
=
CapaFactory
.
create
(
rerandomize
=
rerandomize
,
done
=
True
)
module
=
CapaFactory
.
create
(
rerandomize
=
rerandomize
,
done
=
True
)
# Try to save
get_request_dict
=
{
CapaFactory
.
input_key
():
'3.14'
}
result
=
module
.
save_problem
(
get_request_dict
)
# Try to save
get_request_dict
=
{
CapaFactory
.
input_key
():
'3.14'
}
result
=
module
.
save_problem
(
get_request_dict
)
# Expect that we succeed
self
.
assertTrue
(
'success'
in
result
and
result
[
'success'
])
# Expect that we succeed
self
.
assertTrue
(
'success'
in
result
and
result
[
'success'
])
def
test_check_button_name
(
self
):
...
...
@@ -1066,7 +1072,7 @@ class CapaModuleTest(unittest.TestCase):
# If user submitted a problem but hasn't reset,
# do NOT show the check button
# Note: we can only reset when rerandomize="always" or "true"
module
=
CapaFactory
.
create
(
rerandomize
=
"always"
,
done
=
True
)
module
=
CapaFactory
.
create
(
rerandomize
=
RANDOMIZATION
.
ALWAYS
,
done
=
True
)
self
.
assertFalse
(
module
.
should_show_check_button
())
module
=
CapaFactory
.
create
(
rerandomize
=
"true"
,
done
=
True
)
...
...
@@ -1080,13 +1086,13 @@ class CapaModuleTest(unittest.TestCase):
# and we do NOT have a reset button, then we can show the check button
# Setting rerandomize to "never" or "false" ensures that the reset button
# is not shown
module
=
CapaFactory
.
create
(
rerandomize
=
"never"
,
done
=
True
)
module
=
CapaFactory
.
create
(
rerandomize
=
RANDOMIZATION
.
NEVER
,
done
=
True
)
self
.
assertTrue
(
module
.
should_show_check_button
())
module
=
CapaFactory
.
create
(
rerandomize
=
"false"
,
done
=
True
)
self
.
assertTrue
(
module
.
should_show_check_button
())
module
=
CapaFactory
.
create
(
rerandomize
=
"per_student"
,
done
=
True
)
module
=
CapaFactory
.
create
(
rerandomize
=
RANDOMIZATION
.
PER_STUDENT
,
done
=
True
)
self
.
assertTrue
(
module
.
should_show_check_button
())
def
test_should_show_reset_button
(
self
):
...
...
@@ -1101,30 +1107,36 @@ class CapaModuleTest(unittest.TestCase):
module
=
CapaFactory
.
create
(
attempts
=
attempts
,
max_attempts
=
attempts
,
done
=
True
)
self
.
assertFalse
(
module
.
should_show_reset_button
())
#
If we're NOT randomizing, then do NOT
show the reset button
module
=
CapaFactory
.
create
(
rerandomize
=
"never"
,
done
=
True
)
self
.
assert
Fals
e
(
module
.
should_show_reset_button
())
#
pre studio default value, DO
show the reset button
module
=
CapaFactory
.
create
(
rerandomize
=
RANDOMIZATION
.
ALWAYS
,
done
=
True
)
self
.
assert
Tru
e
(
module
.
should_show_reset_button
())
# If we're NOT randomizing, then do NOT show the reset button
module
=
CapaFactory
.
create
(
rerandomize
=
"per_student"
,
done
=
True
)
self
.
assertFalse
(
module
.
should_show_reset_button
())
# If survey question for capa (max_attempts = 0),
# DO show the reset button
module
=
CapaFactory
.
create
(
rerandomize
=
RANDOMIZATION
.
ALWAYS
,
max_attempts
=
0
,
done
=
True
)
self
.
assertTrue
(
module
.
should_show_reset_button
())
# If we're NOT randomizing, then do NOT show the reset button
module
=
CapaFactory
.
create
(
rerandomize
=
"false"
,
done
=
True
)
self
.
assertFalse
(
module
.
should_show_reset_button
())
# If the question is not correct
# DO show the reset button
module
=
CapaFactory
.
create
(
rerandomize
=
RANDOMIZATION
.
ALWAYS
,
max_attempts
=
0
,
done
=
True
,
correct
=
False
)
self
.
assertTrue
(
module
.
should_show_reset_button
())
# If the
user hasn't submitted an answer yet,
#
then do NOT
show the reset button
module
=
CapaFactory
.
create
(
done
=
Fals
e
)
# If the
question is correct and randomization is never
#
DO not
show the reset button
module
=
CapaFactory
.
create
(
rerandomize
=
RANDOMIZATION
.
NEVER
,
max_attempts
=
0
,
done
=
True
,
correct
=
Tru
e
)
self
.
assertFalse
(
module
.
should_show_reset_button
())
# pre studio default value, DO show the reset button
module
=
CapaFactory
.
create
(
rerandomize
=
"always"
,
done
=
True
)
# If the question is correct and randomization is always
# Show the reset button
module
=
CapaFactory
.
create
(
rerandomize
=
RANDOMIZATION
.
ALWAYS
,
max_attempts
=
0
,
done
=
True
,
correct
=
True
)
self
.
assertTrue
(
module
.
should_show_reset_button
())
# If survey question for capa (max_attempts = 0),
# DO show the reset button
module
=
CapaFactory
.
create
(
rerandomize
=
"always"
,
max_attempts
=
0
,
done
=
True
)
# Don't show reset button if randomization is turned on and the question is not done
module
=
CapaFactory
.
create
(
rerandomize
=
RANDOMIZATION
.
ALWAYS
,
show_reset_button
=
False
,
done
=
False
)
self
.
assertFalse
(
module
.
should_show_reset_button
())
# Show reset button if randomization is turned on and the problem is done
module
=
CapaFactory
.
create
(
rerandomize
=
RANDOMIZATION
.
ALWAYS
,
show_reset_button
=
False
,
done
=
True
)
self
.
assertTrue
(
module
.
should_show_reset_button
())
def
test_should_show_save_button
(
self
):
...
...
@@ -1140,7 +1152,7 @@ class CapaModuleTest(unittest.TestCase):
self
.
assertFalse
(
module
.
should_show_save_button
())
# If user submitted a problem but hasn't reset, do NOT show the save button
module
=
CapaFactory
.
create
(
rerandomize
=
"always"
,
done
=
True
)
module
=
CapaFactory
.
create
(
rerandomize
=
RANDOMIZATION
.
ALWAYS
,
done
=
True
)
self
.
assertFalse
(
module
.
should_show_save_button
())
module
=
CapaFactory
.
create
(
rerandomize
=
"true"
,
done
=
True
)
...
...
@@ -1149,27 +1161,27 @@ class CapaModuleTest(unittest.TestCase):
# If the user has unlimited attempts and we are not randomizing,
# then do NOT show a save button
# because they can keep using "Check"
module
=
CapaFactory
.
create
(
max_attempts
=
None
,
rerandomize
=
"never"
,
done
=
False
)
module
=
CapaFactory
.
create
(
max_attempts
=
None
,
rerandomize
=
RANDOMIZATION
.
NEVER
,
done
=
False
)
self
.
assertFalse
(
module
.
should_show_save_button
())
module
=
CapaFactory
.
create
(
max_attempts
=
None
,
rerandomize
=
"false"
,
done
=
True
)
self
.
assertFalse
(
module
.
should_show_save_button
())
module
=
CapaFactory
.
create
(
max_attempts
=
None
,
rerandomize
=
"per_student"
,
done
=
True
)
module
=
CapaFactory
.
create
(
max_attempts
=
None
,
rerandomize
=
RANDOMIZATION
.
PER_STUDENT
,
done
=
True
)
self
.
assertFalse
(
module
.
should_show_save_button
())
# pre-studio default, DO show the save button
module
=
CapaFactory
.
create
(
rerandomize
=
"always"
,
done
=
False
)
module
=
CapaFactory
.
create
(
rerandomize
=
RANDOMIZATION
.
ALWAYS
,
done
=
False
)
self
.
assertTrue
(
module
.
should_show_save_button
())
# If we're not randomizing and we have limited attempts, then we can save
module
=
CapaFactory
.
create
(
rerandomize
=
"never"
,
max_attempts
=
2
,
done
=
True
)
module
=
CapaFactory
.
create
(
rerandomize
=
RANDOMIZATION
.
NEVER
,
max_attempts
=
2
,
done
=
True
)
self
.
assertTrue
(
module
.
should_show_save_button
())
module
=
CapaFactory
.
create
(
rerandomize
=
"false"
,
max_attempts
=
2
,
done
=
True
)
self
.
assertTrue
(
module
.
should_show_save_button
())
module
=
CapaFactory
.
create
(
rerandomize
=
"per_student"
,
max_attempts
=
2
,
done
=
True
)
module
=
CapaFactory
.
create
(
rerandomize
=
RANDOMIZATION
.
PER_STUDENT
,
max_attempts
=
2
,
done
=
True
)
self
.
assertTrue
(
module
.
should_show_save_button
())
# If survey question for capa (max_attempts = 0),
...
...
@@ -1197,7 +1209,7 @@ class CapaModuleTest(unittest.TestCase):
# then show it even if we would ordinarily
# require a reset first
module
=
CapaFactory
.
create
(
force_save_button
=
"true"
,
rerandomize
=
"always"
,
rerandomize
=
RANDOMIZATION
.
ALWAYS
,
done
=
True
)
self
.
assertTrue
(
module
.
should_show_save_button
())
...
...
@@ -1331,48 +1343,66 @@ class CapaModuleTest(unittest.TestCase):
context
=
render_args
[
1
]
self
.
assertTrue
(
error_msg
in
context
[
'problem'
][
'html'
])
def
test_random_seed_no_change
(
self
):
@ddt.data
(
'false'
,
'true'
,
RANDOMIZATION
.
NEVER
,
RANDOMIZATION
.
PER_STUDENT
,
RANDOMIZATION
.
ALWAYS
,
RANDOMIZATION
.
ONRESET
)
def
test_random_seed_no_change
(
self
,
rerandomize
):
# Run the test for each possible rerandomize value
for
rerandomize
in
[
'false'
,
'never'
,
'per_student'
,
'always'
,
'true'
,
'onreset'
]:
module
=
CapaFactory
.
create
(
rerandomize
=
rerandomize
)
# Get the seed
# By this point, the module should have persisted the seed
seed
=
module
.
seed
self
.
assertTrue
(
seed
is
not
None
)
module
=
CapaFactory
.
create
(
rerandomize
=
rerandomize
)
# If we're not rerandomizing, the seed is always set
# to the same value (1)
if
rerandomize
in
[
'never'
]:
self
.
assertEqual
(
seed
,
1
,
msg
=
"Seed should always be 1 when rerandomize='
%
s'"
%
rerandomize
)
# Get the seed
# By this point, the module should have persisted the seed
seed
=
module
.
seed
self
.
assertTrue
(
seed
is
not
None
)
# Check the problem
get_request_dict
=
{
CapaFactory
.
input_key
():
'3.14'
}
module
.
check_problem
(
get_request_dict
)
# If we're not rerandomizing, the seed is always set
# to the same value (1)
if
rerandomize
==
RANDOMIZATION
.
NEVER
:
self
.
assertEqual
(
seed
,
1
,
msg
=
"Seed should always be 1 when rerandomize='
%
s'"
%
rerandomize
)
# Expect that the seed is the same
self
.
assertEqual
(
seed
,
module
.
seed
)
# Check the problem
get_request_dict
=
{
CapaFactory
.
input_key
():
'3.14'
}
module
.
check_problem
(
get_request_dict
)
# Save the problem
module
.
save_problem
(
get_request_dict
)
# Expect that the seed is the same
self
.
assertEqual
(
seed
,
module
.
seed
)
# Expect that the seed is the same
self
.
assertEqual
(
seed
,
module
.
seed
)
# Save the problem
module
.
save_problem
(
get_request_dict
)
# Expect that the seed is the same
self
.
assertEqual
(
seed
,
module
.
seed
)
@ddt.data
(
'false'
,
'true'
,
RANDOMIZATION
.
NEVER
,
RANDOMIZATION
.
PER_STUDENT
,
RANDOMIZATION
.
ALWAYS
,
RANDOMIZATION
.
ONRESET
)
def
test_random_seed_with_reset
(
self
,
rerandomize
):
"""
Run the test for each possible rerandomize value
"""
def
test_random_seed_with_reset
(
self
):
def
_reset_and_get_seed
(
module
):
'''
"""
Reset the XModule and return the module's seed
'''
"""
# Simulate submitting an attempt
# We need to do this, or reset_problem() will
# fail
with a complaint that we haven't
submitted
# fail
because it won't re-randomize until the problem has been
submitted
# the problem yet.
module
.
done
=
True
...
...
@@ -1397,45 +1427,83 @@ class CapaModuleTest(unittest.TestCase):
break
return
success
# Run the test for each possible rerandomize value
for
rerandomize
in
[
'never'
,
'false'
,
'per_student'
,
'always'
,
'true'
,
'onreset'
]:
module
=
CapaFactory
.
create
(
rerandomize
=
rerandomize
)
module
=
CapaFactory
.
create
(
rerandomize
=
rerandomize
,
done
=
True
)
# Get the seed
# By this point, the module should have persisted the seed
seed
=
module
.
seed
self
.
assertTrue
(
seed
is
not
None
)
# We do NOT want the seed to reset if rerandomize
# is set to 'never' -- it should still be 1
# The seed also stays the same if we're randomizing
# 'per_student': the same student should see the same problem
if
rerandomize
in
[
RANDOMIZATION
.
NEVER
,
'false'
,
RANDOMIZATION
.
PER_STUDENT
]:
self
.
assertEqual
(
seed
,
_reset_and_get_seed
(
module
))
# Otherwise, we expect the seed to change
# to another valid seed
else
:
# Since there's a small chance we might get the
# same seed again, give it 5 chances
# to generate a different seed
success
=
_retry_and_check
(
5
,
lambda
:
_reset_and_get_seed
(
module
)
!=
seed
)
self
.
assertTrue
(
module
.
seed
is
not
None
)
msg
=
'Could not get a new seed from reset after 5 tries'
self
.
assertTrue
(
success
,
msg
)
@ddt.data
(
'false'
,
'true'
,
RANDOMIZATION
.
NEVER
,
RANDOMIZATION
.
PER_STUDENT
,
RANDOMIZATION
.
ALWAYS
,
RANDOMIZATION
.
ONRESET
)
def
test_random_seed_with_reset_question_unsubmitted
(
self
,
rerandomize
):
"""
Run the test for each possible rerandomize value
"""
def
_reset_and_get_seed
(
module
):
"""
Reset the XModule and return the module's seed
"""
# Get the seed
# By this point, the module should have persisted the seed
seed
=
module
.
seed
self
.
assertTrue
(
seed
is
not
None
)
# Reset the problem
# By default, the problem is instantiated as unsubmitted
module
.
reset_problem
({})
# We do NOT want the seed to reset if rerandomize
# is set to 'never' -- it should still be 1
# The seed also stays the same if we're randomizing
# 'per_student': the same student should see the same problem
if
rerandomize
in
[
'never'
,
'false'
,
'per_student'
]:
self
.
assertEqual
(
seed
,
_reset_and_get_seed
(
module
))
# Return the seed
return
module
.
seed
# Otherwise, we expect the seed to change
# to another valid seed
else
:
module
=
CapaFactory
.
create
(
rerandomize
=
rerandomize
,
done
=
False
)
# Since there's a small chance we might get the
# same seed again, give it 5 chances
# to generate a different
seed
success
=
_retry_and_check
(
5
,
lambda
:
_reset_and_get_seed
(
module
)
!=
seed
)
# Get the seed
# By this point, the module should have persisted the seed
seed
=
module
.
seed
self
.
assertTrue
(
seed
is
not
None
)
self
.
assertTrue
(
module
.
seed
is
not
None
)
msg
=
'Could not get a new seed from reset after 5 tries'
self
.
assertTrue
(
success
,
msg
)
#the seed should never change because the student hasn't finished the problem
self
.
assertEqual
(
seed
,
_reset_and_get_seed
(
module
))
def
test_random_seed_bins
(
self
):
@ddt.data
(
RANDOMIZATION
.
ALWAYS
,
RANDOMIZATION
.
PER_STUDENT
,
'true'
,
RANDOMIZATION
.
ONRESET
)
def
test_random_seed_bins
(
self
,
rerandomize
):
# Assert that we are limiting the number of possible seeds.
# Check the conditions that generate random seeds
for
rerandomize
in
[
'always'
,
'per_student'
,
'true'
,
'onreset'
]:
# Get a bunch of seeds, they should all be in 0-999.
for
i
in
range
(
200
):
module
=
CapaFactory
.
create
(
rerandomize
=
rerandomize
)
assert
0
<=
module
.
seed
<
1000
# Get a bunch of seeds, they should all be in 0-999.
i
=
200
while
i
>
0
:
module
=
CapaFactory
.
create
(
rerandomize
=
rerandomize
)
assert
0
<=
module
.
seed
<
1000
i
-=
1
@patch
(
'xmodule.capa_base.log'
)
@patch
(
'xmodule.capa_base.Progress'
)
...
...
@@ -1765,7 +1833,7 @@ class TestProblemCheckTracking(unittest.TestCase):
def
test_rerandomized_inputs
(
self
):
factory
=
CapaFactory
module
=
factory
.
create
(
rerandomize
=
'always'
)
module
=
factory
.
create
(
rerandomize
=
RANDOMIZATION
.
ALWAYS
)
answer_input_dict
=
{
factory
.
input_key
(
2
):
'3.14'
...
...
lms/djangoapps/courseware/features/problems.feature
View file @
3d1c54fe
...
...
@@ -72,37 +72,77 @@ Feature: LMS.Answer problems
Scenario
:
I
can reset a problem
Given
I am viewing a
"<ProblemType>"
problem
Given
I am viewing a randomization
"<Randomization>"
"<ProblemType>"
problem with reset button on
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
|
Randomization
|
|
drop
down
|
correct
|
always
|
|
drop
down
|
incorrect
|
always
|
|
multiple
choice
|
correct
|
always
|
|
multiple
choice
|
incorrect
|
always
|
|
checkbox
|
correct
|
always
|
|
checkbox
|
incorrect
|
always
|
|
radio
|
correct
|
always
|
|
radio
|
incorrect
|
always
|
|
string
|
correct
|
always
|
|
string
|
incorrect
|
always
|
|
numerical
|
correct
|
always
|
|
numerical
|
incorrect
|
always
|
|
formula
|
correct
|
always
|
|
formula
|
incorrect
|
always
|
|
script
|
correct
|
always
|
|
script
|
incorrect
|
always
|
|
radio_text
|
correct
|
always
|
|
radio_text
|
incorrect
|
always
|
|
checkbox_text
|
correct
|
always
|
|
checkbox_text
|
incorrect
|
always
|
|
image
|
correct
|
always
|
|
image
|
incorrect
|
always
|
Scenario
:
I
can reset a non-randomized problem that I answer incorrectly
Given
I am viewing a randomization
"<Randomization>"
"<ProblemType>"
problem with reset button on
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
|
|
drop
down
|
correct
|
|
drop
down
|
incorrect
|
|
multiple
choice
|
correct
|
|
multiple
choice
|
incorrect
|
|
checkbox
|
correct
|
|
checkbox
|
incorrect
|
|
radio
|
correct
|
|
radio
|
incorrect
|
|
string
|
correct
|
|
string
|
incorrect
|
|
numerical
|
correct
|
|
numerical
|
incorrect
|
|
formula
|
correct
|
|
formula
|
incorrect
|
|
script
|
correct
|
|
script
|
incorrect
|
|
radio_text
|
correct
|
|
radio_text
|
incorrect
|
|
checkbox_text
|
correct
|
|
checkbox_text
|
incorrect
|
|
image
|
correct
|
|
image
|
incorrect
|
|
ProblemType
|
Correctness
|
Randomization
|
|
drop
down
|
incorrect
|
never
|
|
drop
down
|
incorrect
|
never
|
|
multiple
choice
|
incorrect
|
never
|
|
checkbox
|
incorrect
|
never
|
|
radio
|
incorrect
|
never
|
|
string
|
incorrect
|
never
|
|
numerical
|
incorrect
|
never
|
|
formula
|
incorrect
|
never
|
|
script
|
incorrect
|
never
|
|
radio_text
|
incorrect
|
never
|
|
checkbox_text
|
incorrect
|
never
|
|
image
|
incorrect
|
never
|
Scenario
:
The reset button doesn't show up
Given
I am viewing a randomization
"<Randomization>"
"<ProblemType>"
problem with reset button on
And
I answer a
"<ProblemType>"
problem
"<Correctness>ly"
Then
The
"Reset"
button does not appear
Examples
:
|
ProblemType
|
Correctness
|
Randomization
|
|
drop
down
|
correct
|
never
|
|
multiple
choice
|
correct
|
never
|
|
checkbox
|
correct
|
never
|
|
radio
|
correct
|
never
|
|
string
|
correct
|
never
|
|
numerical
|
correct
|
never
|
|
formula
|
correct
|
never
|
|
script
|
correct
|
never
|
|
radio_text
|
correct
|
never
|
|
checkbox_text
|
correct
|
never
|
|
image
|
correct
|
never
|
Scenario
:
I
can answer a problem with one attempt correctly and not reset
Given
I am viewing a
"multiple choice"
problem with
"1"
attempt
...
...
@@ -115,6 +155,12 @@ Feature: LMS.Answer problems
When
I answer a
"multiple choice"
problem
"correctly"
Then
The
"Reset"
button does appear
Scenario
:
I
can answer a problem with multiple attempts correctly but cannot reset because randomization is off
Given
I am viewing a randomization
"never"
"multiple choice"
problem with
"3"
attempts with reset
Then
I should see
"You have used 0 of 3 submissions"
somewhere in the page
When
I answer a
"multiple choice"
problem
"correctly"
Then
The
"Reset"
button does not appear
Scenario
:
I
can view how many attempts I have left on a problem
Given
I am viewing a
"multiple choice"
problem with
"3"
attempts
Then
I should see
"You have used 0 of 3 submissions"
somewhere in the page
...
...
@@ -165,6 +211,34 @@ Feature: LMS.Answer problems
|
image
|
correct
|
1/1
point
|
1
point
possible
|
|
image
|
incorrect
|
1
point
possible
|
1
point
possible
|
Scenario
:
I
can see my score on a problem when I answer it and after I reset it
Given
I am viewing a
"<ProblemType>"
problem with randomization
"<Randomization>"
with reset button on
When
I answer a
"<ProblemType>"
problem
"<Correctness>ly"
Then
I should see a score of
"<Score>"
When
I reset the problem
Then
I should see a score of
"<Points Possible>"
Examples
:
|
ProblemType
|
Correctness
|
Score
|
Points
Possible
|
Randomization
|
|
drop
down
|
correct
|
1/1
point
|
1
point
possible
|
never
|
|
drop
down
|
incorrect
|
1
point
possible
|
1
point
possible
|
never
|
|
multiple
choice
|
correct
|
1/1
point
|
1
point
possible
|
never
|
|
multiple
choice
|
incorrect
|
1
point
possible
|
1
point
possible
|
never
|
|
checkbox
|
correct
|
1/1
point
|
1
point
possible
|
never
|
|
checkbox
|
incorrect
|
1
point
possible
|
1
point
possible
|
never
|
|
radio
|
correct
|
1/1
point
|
1
point
possible
|
never
|
|
radio
|
incorrect
|
1
point
possible
|
1
point
possible
|
never
|
|
string
|
correct
|
1/1
point
|
1
point
possible
|
never
|
|
string
|
incorrect
|
1
point
possible
|
1
point
possible
|
never
|
|
numerical
|
correct
|
1/1
point
|
1
point
possible
|
never
|
|
numerical
|
incorrect
|
1
point
possible
|
1
point
possible
|
never
|
|
formula
|
correct
|
1/1
point
|
1
point
possible
|
never
|
|
formula
|
incorrect
|
1
point
possible
|
1
point
possible
|
never
|
|
script
|
correct
|
2/2
points
|
2
points
possible
|
never
|
|
script
|
incorrect
|
2
points
possible
|
2
points
possible
|
never
|
|
image
|
correct
|
1/1
point
|
1
point
possible
|
never
|
|
image
|
incorrect
|
1
point
possible
|
1
point
possible
|
never
|
Scenario
:
I
can see my score on a problem to which I submit a blank answer
Given
I am viewing a
"<ProblemType>"
problem
When
I check a problem
...
...
lms/djangoapps/courseware/features/problems.py
View file @
3d1c54fe
...
...
@@ -26,6 +26,13 @@ def view_problem_with_attempts(step, problem_type, attempts):
_view_problem
(
step
,
problem_type
,
{
'max_attempts'
:
attempts
})
@step
(
u'I am viewing a randomization "([^"]*)" "([^"]*)" problem with "([^"]*)" attempts with reset'
)
def
view_problem_attempts_reset
(
step
,
randomization
,
problem_type
,
attempts
,
):
_view_problem
(
step
,
problem_type
,
{
'max_attempts'
:
attempts
,
'rerandomize'
:
randomization
,
'show_reset_button'
:
True
})
@step
(
u'I am viewing a "([^"]*)" that shows the answer "([^"]*)"'
)
def
view_problem_with_show_answer
(
step
,
problem_type
,
answer
):
_view_problem
(
step
,
problem_type
,
{
'showanswer'
:
answer
})
...
...
@@ -36,6 +43,11 @@ def view_problem(step, problem_type):
_view_problem
(
step
,
problem_type
)
@step
(
u'I am viewing a randomization "([^"]*)" "([^"]*)" problem with reset button on'
)
def
view_random_reset_problem
(
step
,
randomization
,
problem_type
):
_view_problem
(
step
,
problem_type
,
{
'rerandomize'
:
randomization
,
'show_reset_button'
:
True
})
@step
(
u'External graders respond "([^"]*)"'
)
def
set_external_grader_response
(
step
,
correctness
):
assert
(
correctness
in
[
'correct'
,
'incorrect'
])
...
...
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